/*-------------------------------------------------------------------------
 *
 * jsonfuncs.c
 *		处理 JSON 数据类型的功能。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/backend/utils/adt/jsonfuncs.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <limits.h>

#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "common/jsonapi.h"
#include "common/string.h"
#include "fmgr.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/hsearch.h"
#include "utils/json.h"
#include "utils/jsonb.h"
#include "utils/jsonfuncs.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/typcache.h"

/* setPath 可用的操作 */
#define JB_PATH_CREATE					0x0001
#define JB_PATH_DELETE					0x0002
#define JB_PATH_REPLACE					0x0004
#define JB_PATH_INSERT_BEFORE			0x0008
#define JB_PATH_INSERT_AFTER			0x0010
#define JB_PATH_CREATE_OR_INSERT \
	(JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)
#define JB_PATH_FILL_GAPS				0x0020
#define JB_PATH_CONSISTENT_POSITION		0x0040

/* json_object_keys 的状态 */
typedef struct OkeysState
{
	JsonLexContext *lex;
	char	  **result;
	int			result_size;
	int			result_count;
	int			sent_count;
} OkeysState;

/* iterate_json_values 函数的状态 */
typedef struct IterateJsonStringValuesState
{
	JsonLexContext *lex;
	JsonIterateStringValuesAction action;	/* 将应用于每个 JSON 值的操作 */
	void	   *action_state;	/* 任何必要的迭代上下文 */
	uint32		flags;			/* 我们想要从 json 中迭代什么样的元素 */
} IterateJsonStringValuesState;

/* transform_json_string_values 函数的状态 */
typedef struct TransformJsonStringValuesState
{
	JsonLexContext *lex;
	StringInfo	strval;			/* 结果 json */
	JsonTransformStringValuesAction action; /* 将应用于每个 JSON 值的操作 */
	void	   *action_state;	/* 转换所需的任何必要上下文 */
} TransformJsonStringValuesState;

/* json_get* 函数的状态 */
typedef struct GetState
{
	JsonLexContext *lex;
	text	   *tresult;
	char	   *result_start;
	bool		normalize_results;
	bool		next_scalar;
	int			npath;			/* 每个路径相关数组的长度 */
	char	  **path_names;		/* 正在寻找的字段名 */
	int		   *path_indexes;	/* 正在寻找的数组索引 */
	bool	   *pathok;			/* 路径是否与当前深度匹配？ */
	int		   *array_cur_index;	/* 每个路径级别的当前元素索引 */
} GetState;

/* json_array_length 的状态 */
typedef struct AlenState
{
	JsonLexContext *lex;
	int			count;
} AlenState;

/* json_each 的状态 */
typedef struct EachState
{
	JsonLexContext *lex;
	Tuplestorestate *tuple_store;
	TupleDesc	ret_tdesc;
	MemoryContext tmp_cxt;
	char	   *result_start;
	bool		normalize_results;
	bool		next_scalar;
	char	   *normalized_scalar;
} EachState;

/* json_array_elements 的状态 */
typedef struct ElementsState
{
	JsonLexContext *lex;
	const char *function_name;
	Tuplestorestate *tuple_store;
	TupleDesc	ret_tdesc;
	MemoryContext tmp_cxt;
	char	   *result_start;
	bool		normalize_results;
	bool		next_scalar;
	char	   *normalized_scalar;
} ElementsState;

/* get_json_object_as_hash 的状态 */
typedef struct JHashState
{
	JsonLexContext *lex;
	const char *function_name;
	HTAB	   *hash;
	char	   *saved_scalar;
	char	   *save_json_start;
	JsonTokenType saved_token_type;
} JHashState;

/* 哈希表元素 */
typedef struct JsonHashEntry
{
	char		fname[NAMEDATALEN]; /* 哈希键（必须是第一个） */
	char	   *val;
	JsonTokenType type;
} JsonHashEntry;

/* 用于缓存 populate_scalar() 所需的 I/O 元数据的结构 */
typedef struct ScalarIOData
{
	Oid			typioparam;
	FmgrInfo	typiofunc;
} ScalarIOData;

/* 这两个结构是递归使用的 */
typedef struct ColumnIOData ColumnIOData;
typedef struct RecordIOData RecordIOData;

/* 用于缓存 populate_array() 所需的元数据的结构 */
typedef struct ArrayIOData
{
	ColumnIOData *element_info; /* 元数据缓存 */
	Oid			element_type;	/* 数组元素类型 ID */
	int32		element_typmod; /* 数组元素类型修饰符 */
} ArrayIOData;

/* 用于缓存 populate_composite() 所需的元数据的结构 */
typedef struct CompositeIOData
{
	/*
	 * 我们在这里使用 RecordIOData 的指针，因为可变长度结构
	 * RecordIOData 不能直接用于 ColumnIOData.io 联合
	 */
	RecordIOData *record_io;	/* populate_record() 的元数据缓存 */
	TupleDesc	tupdesc;		/* 缓存的元组描述符 */
	/* 这些字段仅在复合的域上与目标类型不同： */
	Oid			base_typid;		/* 基类型 ID */
	int32		base_typmod;	/* 基本类型修饰符 */
	/* 该字段仅在目标类型为复合类型的域时使用： */
	void	   *domain_info;	/* opaque cache for domain checks */
} CompositeIOData;

/* 用于缓存 populate_domain() 所需的元数据的结构体 */
typedef struct DomainIOData
{
	ColumnIOData *base_io;		/* 元数据缓存 */
	Oid			base_typid;		/* 基类型 ID */
	int32		base_typmod;	/* 基本类型修饰符 */
	void	   *domain_info;	/* opaque cache for domain checks */
} DomainIOData;

/* 枚举类型分类 */
typedef enum TypeCat
{
	TYPECAT_SCALAR = 's',
	TYPECAT_ARRAY = 'a',
	TYPECAT_COMPOSITE = 'c',
	TYPECAT_COMPOSITE_DOMAIN = 'C',
	TYPECAT_DOMAIN = 'd'
} TypeCat;

/* 这两个来自 hstore / record_out，用于 populate_record* */

/* 用于缓存 populate_record_field() 所需的记录元数据的结构体 */
struct ColumnIOData
{
	Oid			typid;			/* 列类型 ID */
	int32		typmod;			/* 列类型修饰符 */
	TypeCat		typcat;			/* 列类型类别 */
	ScalarIOData scalar_io;		/* 用于通过输入函数直接转换的元数据缓存 */
	union
	{
		ArrayIOData array;
		CompositeIOData composite;
		DomainIOData domain;
	}			io;				/* 用于各种列类型类别的元数据缓存 */
};

/* 用于缓存 populate_record() 所需的记录元数据的结构体 */
struct RecordIOData
{
	Oid			record_type;
	int32		record_typmod;
	int			ncolumns;
	ColumnIOData columns[FLEXIBLE_ARRAY_MEMBER];
};

/* 用于 populate_record_worker 和 populate_recordset_worker 的每查询缓存 */
typedef struct PopulateRecordCache
{
	Oid			argtype;		/* 记录参数的声明类型 */
	ColumnIOData c;				/* 用于 populate_composite() 的元数据缓存 */
	MemoryContext fn_mcxt;		/* 该信息存储的位置 */
} PopulateRecordCache;

/* 用于 populate_recordset 的每调用状态 */
typedef struct PopulateRecordsetState
{
	JsonLexContext *lex;
	const char *function_name;
	HTAB	   *json_hash;
	char	   *saved_scalar;
	char	   *save_json_start;
	JsonTokenType saved_token_type;
	Tuplestorestate *tuple_store;
	HeapTupleHeader rec;
	PopulateRecordCache *cache;
} PopulateRecordsetState;

/* 用于 populate_array_json() 和 populate_array_dim_jsonb() 的公共数据 */
typedef struct PopulateArrayContext
{
	ArrayBuildState *astate;	/* 数组构建状态 */
	ArrayIOData *aio;			/* 元数据缓存 */
	MemoryContext acxt;			/* 数组构建内存上下文 */
	MemoryContext mcxt;			/* 缓存内存上下文 */
	const char *colname;		/* 仅用于诊断 */
	int		   *dims;			/* 维度 */
	int		   *sizes;			/* 当前维度计数器 */
	int			ndims;			/* 维度数量 */
} PopulateArrayContext;

/* 用于 populate_array_json() 的状态 */
typedef struct PopulateArrayState
{
	JsonLexContext *lex;		/* json 词法分析器 */
	PopulateArrayContext *ctx;	/* 设置 */
	char	   *element_start;	/* 当前数组元素的开始 */
	char	   *element_scalar; /* 当前数组元素的令牌，如果它是一个 
								   * 标量 */
	JsonTokenType element_type; /* 当前数组元素类型 */
} PopulateArrayState;

/* 用于 json_strip_nulls 的状态 */
typedef struct StripnullState
{
	JsonLexContext *lex;
	StringInfo	strval;
	bool		skip_next_null;
} StripnullState;

/* 用于通用 json/jsonb 值传递的结构体 */
typedef struct JsValue
{
	bool		is_json;		/* json/jsonb */
	union
	{
		struct
		{
			char	   *str;	/* json 字符串 */
			int			len;	/* json 字符串长度，或 -1 如果是以 null 结尾 */
			JsonTokenType type; /* json 类型 */
		}			json;		/* json 值 */

		JsonbValue *jsonb;		/* jsonb 值 */
	}			val;
} JsValue;

typedef struct JsObject
{
	bool		is_json;		/* json/jsonb */
	union
	{
		HTAB	   *json_hash;
		JsonbContainer *jsonb_cont;
	}			val;
} JsObject;

/* 用于测试 JsValue 属性的有用宏 */
#define JsValueIsNull(jsv) \
	((jsv)->is_json ?  \
		(!(jsv)->val.json.str || (jsv)->val.json.type == JSON_TOKEN_NULL) : \
		(!(jsv)->val.jsonb || (jsv)->val.jsonb->type == jbvNull))

#define JsValueIsString(jsv) \
	((jsv)->is_json ? (jsv)->val.json.type == JSON_TOKEN_STRING \
		: ((jsv)->val.jsonb && (jsv)->val.jsonb->type == jbvString))

#define JsObjectIsEmpty(jso) \
	((jso)->is_json \
		? hash_get_num_entries((jso)->val.json_hash) == 0 \
		: ((jso)->val.jsonb_cont == NULL || \
		   JsonContainerSize((jso)->val.jsonb_cont) == 0))

#define JsObjectFree(jso) \
	do { \
		if ((jso)->is_json) \
			hash_destroy((jso)->val.json_hash); \
	} while (0)

static int	fc_report_json_context(JsonLexContext *fc_lex);

/* json_object_keys 的语义操作函数 */
static void fc_okeys_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_okeys_array_start(void *fc_state);
static void fc_okeys_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);

/* json_get* 函数的语义操作函数 */
static void get_object_start(void *fc_state);
static void get_object_end(void *fc_state);
static void get_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);
static void get_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull);
static void get_array_start(void *fc_state);
static void get_array_end(void *fc_state);
static void get_array_element_start(void *fc_state, bool fc_isnull);
static void get_array_element_end(void *fc_state, bool fc_isnull);
static void get_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);

/* json getter 函数的通用工作函数 */
static Datum get_path_all(FunctionCallInfo fcinfo, bool fc_as_text);
static text *get_worker(text *fc_json, char **fc_tpath, int *fc_ipath, int fc_npath,
						bool fc_normalize_results);
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool fc_as_text);
static text *fc_JsonbValueAsText(JsonbValue *fc_v);

/* json_array_length 的语义操作函数 */
static void fc_alen_object_start(void *fc_state);
static void fc_alen_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);
static void fc_alen_array_element_start(void *fc_state, bool fc_isnull);

/* json{b}_each* 函数的通用工作函数 */
static Datum fc_each_worker(FunctionCallInfo fcinfo, bool fc_as_text);
static Datum fc_each_worker_jsonb(FunctionCallInfo fcinfo, const char *fc_funcname,
							   bool fc_as_text);

/* json_each 的语义操作函数 */
static void fc_each_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_each_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_each_array_start(void *fc_state);
static void fc_each_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);

/* json{b}_array_elements_* 函数的通用工作函数 */
static Datum fc_elements_worker(FunctionCallInfo fcinfo, const char *fc_funcname,
							 bool fc_as_text);
static Datum fc_elements_worker_jsonb(FunctionCallInfo fcinfo, const char *fc_funcname,
								   bool fc_as_text);

/* json_array_elements 的语义操作函数 */
static void fc_elements_object_start(void *fc_state);
static void fc_elements_array_element_start(void *fc_state, bool fc_isnull);
static void fc_elements_array_element_end(void *fc_state, bool fc_isnull);
static void fc_elements_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);

/* 将 json 对象转换为哈希表 */
static HTAB *get_json_object_as_hash(char *fc_json, int fc_len, const char *fc_funcname);

/* 填充数组 json 的语义操作 */
static void fc_populate_array_object_start(void *fc__state);
static void fc_populate_array_array_end(void *fc__state);
static void fc_populate_array_element_start(void *fc__state, bool fc_isnull);
static void fc_populate_array_element_end(void *fc__state, bool fc_isnull);
static void fc_populate_array_scalar(void *fc__state, char *fc_token, JsonTokenType fc_tokentype);

/* 将 json 对象作为哈希获取的语义操作函数 */
static void fc_hash_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_hash_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_hash_array_start(void *fc_state);
static void fc_hash_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);

/* 填充记录集的语义操作函数 */
static void fc_populate_recordset_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_populate_recordset_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_populate_recordset_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);
static void fc_populate_recordset_object_start(void *fc_state);
static void fc_populate_recordset_object_end(void *fc_state);
static void fc_populate_recordset_array_start(void *fc_state);
static void fc_populate_recordset_array_element_start(void *fc_state, bool fc_isnull);

/* json_strip_nulls 的语义操作函数 */
static void fc_sn_object_start(void *fc_state);
static void fc_sn_object_end(void *fc_state);
static void fc_sn_array_start(void *fc_state);
static void fc_sn_array_end(void *fc_state);
static void fc_sn_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_sn_array_element_start(void *fc_state, bool fc_isnull);
static void fc_sn_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);

/* 用于填充记录、to_record、填充记录集和 to_recordset 的工作函数 */
static Datum fc_populate_recordset_worker(FunctionCallInfo fcinfo, const char *fc_funcname,
									   bool fc_is_json, bool fc_have_record_arg);
static Datum fc_populate_record_worker(FunctionCallInfo fcinfo, const char *fc_funcname,
									bool fc_is_json, bool fc_have_record_arg);

/* 用于填充记录[集] 的辅助函数 */
static HeapTupleHeader fc_populate_record(TupleDesc fc_tupdesc, RecordIOData **fc_record_p,
									   HeapTupleHeader fc_defaultval, MemoryContext fc_mcxt,
									   JsObject *fc_obj);
static void get_record_type_from_argument(FunctionCallInfo fcinfo,
										  const char *fc_funcname,
										  PopulateRecordCache *fc_cache);
static void get_record_type_from_query(FunctionCallInfo fcinfo,
									   const char *fc_funcname,
									   PopulateRecordCache *fc_cache);
static void fc_JsValueToJsObject(JsValue *fc_jsv, JsObject *fc_jso);
static Datum fc_populate_composite(CompositeIOData *fc_io, Oid fc_typid,
								const char *fc_colname, MemoryContext fc_mcxt,
								HeapTupleHeader fc_defaultval, JsValue *fc_jsv, bool fc_isnull);
static Datum fc_populate_scalar(ScalarIOData *fc_io, Oid fc_typid, int32 fc_typmod, JsValue *fc_jsv);
static void fc_prepare_column_cache(ColumnIOData *fc_column, Oid fc_typid, int32 fc_typmod,
								 MemoryContext fc_mcxt, bool fc_need_scalar);
static Datum fc_populate_record_field(ColumnIOData *fc_col, Oid fc_typid, int32 fc_typmod,
								   const char *fc_colname, MemoryContext fc_mcxt, Datum fc_defaultval,
								   JsValue *fc_jsv, bool *fc_isnull);
static RecordIOData *fc_allocate_record_info(MemoryContext fc_mcxt, int fc_ncolumns);
static bool fc_JsObjectGetField(JsObject *fc_obj, char *fc_field, JsValue *fc_jsv);
static void fc_populate_recordset_record(PopulateRecordsetState *fc_state, JsObject *fc_obj);
static void fc_populate_array_json(PopulateArrayContext *fc_ctx, char *fc_json, int fc_len);
static void fc_populate_array_dim_jsonb(PopulateArrayContext *fc_ctx, JsonbValue *fc_jbv,
									 int fc_ndim);
static void fc_populate_array_report_expected_array(PopulateArrayContext *fc_ctx, int fc_ndim);
static void fc_populate_array_assign_ndims(PopulateArrayContext *fc_ctx, int fc_ndims);
static void fc_populate_array_check_dimension(PopulateArrayContext *fc_ctx, int fc_ndim);
static void fc_populate_array_element(PopulateArrayContext *fc_ctx, int fc_ndim, JsValue *fc_jsv);
static Datum fc_populate_array(ArrayIOData *fc_aio, const char *fc_colname,
							MemoryContext fc_mcxt, JsValue *fc_jsv);
static Datum fc_populate_domain(DomainIOData *fc_io, Oid fc_typid, const char *fc_colname,
							 MemoryContext fc_mcxt, JsValue *fc_jsv, bool fc_isnull);

/* 支持 jsonb_delete、jsonb_set 和 jsonb_concat 的函数 */
static JsonbValue *fc_IteratorConcat(JsonbIterator **fc_it1, JsonbIterator **fc_it2,
								  JsonbParseState **fc_state);
static JsonbValue *fc_setPath(JsonbIterator **fc_it, Datum *fc_path_elems,
						   bool *fc_path_nulls, int fc_path_len,
						   JsonbParseState **fc_st, int fc_level, JsonbValue *fc_newval,
						   int fc_op_type);
static void fc_setPathObject(JsonbIterator **fc_it, Datum *fc_path_elems,
						  bool *fc_path_nulls, int fc_path_len, JsonbParseState **fc_st,
						  int fc_level,
						  JsonbValue *fc_newval, uint32 fc_npairs, int fc_op_type);
static void fc_setPathArray(JsonbIterator **fc_it, Datum *fc_path_elems,
						 bool *fc_path_nulls, int fc_path_len, JsonbParseState **fc_st,
						 int fc_level,
						 JsonbValue *fc_newval, uint32 fc_nelems, int fc_op_type);

/* 支持 iterate_json_values 的函数 */
static void fc_iterate_values_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);
static void fc_iterate_values_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);

/* 支持 transform_json_string_values 的函数 */
static void fc_transform_string_values_object_start(void *fc_state);
static void fc_transform_string_values_object_end(void *fc_state);
static void fc_transform_string_values_array_start(void *fc_state);
static void fc_transform_string_values_array_end(void *fc_state);
static void fc_transform_string_values_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull);
static void fc_transform_string_values_array_element_start(void *fc_state, bool fc_isnull);
static void fc_transform_string_values_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype);

/*
 * pg_parse_json_or_ereport
 *
 * 这个函数类似于 pg_parse_json，不同的是它不返回一个
 * JsonParseErrorType。相反，在发生任何失败的情况下，这个函数将
 * ereport(ERROR)。
 */
void pg_parse_json_or_ereport(JsonLexContext *fc_lex, JsonSemAction *fc_sem)
{
	JsonParseErrorType fc_result;

	fc_result = pg_parse_json(fc_lex, fc_sem);
	if (fc_result != JSON_SUCCESS)
		json_ereport_error(fc_result, fc_lex);
}

/*
 * makeJsonLexContext
 *
 * 这类似于 makeJsonLexContextCstringLen，但它直接接受文本值。
 */
JsonLexContext *
makeJsonLexContext(text *fc_json, bool fc_need_escapes)
{
	/*
	 * 大多数调用者会传递一个去烘烤的数据，但并不清楚他们
	 * 是否都是这样做的。pg_detoast_datum_packed() 是廉价的保险。
	 */
	fc_json = pg_detoast_datum_packed(fc_json);

	return makeJsonLexContextCstringLen(VARDATA_ANY(fc_json),
										VARSIZE_ANY_EXHDR(fc_json),
										GetDatabaseEncoding(),
										fc_need_escapes);
}

/*
 * SQL 函数 json_object_keys
 *
 * 返回对象参数的键集合。
 *
 * 这个 SRF 以每次调用一个值的模式运行。它在第一次调用时处理
 * 对象，并将键简单地存储在一个数组中，数组的大小根据需要扩大。
 * 对于单个对象的键列表，这可能是足够安全的，因为它们的大小
 * 限制为 NAMEDATALEN，且键的数量不太可能大到会产生重大的内存
 * 影响。
 */
Datum jsonb_object_keys(PG_FUNCTION_ARGS)
{
	FuncCallContext *fc_funcctx;
	OkeysState *fc_state;

	if (SRF_IS_FIRSTCALL())
	{
		MemoryContext fc_oldcontext;
		Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
		bool		fc_skipNested = false;
		JsonbIterator *fc_it;
		JsonbValue	fc_v;
		JsonbIteratorToken fc_r;

		if (JB_ROOT_IS_SCALAR(fc_jb))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("cannot call %s on a scalar",
							"jsonb_object_keys")));
		else if (JB_ROOT_IS_ARRAY(fc_jb))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("cannot call %s on an array",
							"jsonb_object_keys")));

		fc_funcctx = SRF_FIRSTCALL_INIT();
		fc_oldcontext = MemoryContextSwitchTo(fc_funcctx->multi_call_memory_ctx);

		fc_state = palloc(sizeof(OkeysState));

		fc_state->result_size = JB_ROOT_COUNT(fc_jb);
		fc_state->result_count = 0;
		fc_state->sent_count = 0;
		fc_state->result = palloc(fc_state->result_size * sizeof(char *));

		fc_it = JsonbIteratorInit(&fc_jb->root);

		while ((fc_r = JsonbIteratorNext(&fc_it, &fc_v, fc_skipNested)) != WJB_DONE)
		{
			fc_skipNested = true;

			if (fc_r == WJB_KEY)
			{
				char	   *fc_cstr;

				fc_cstr = palloc(fc_v.val.string.len + 1 * sizeof(char));
				memcpy(fc_cstr, fc_v.val.string.val, fc_v.val.string.len);
				fc_cstr[fc_v.val.string.len] = '\0';
				fc_state->result[fc_state->result_count++] = fc_cstr;
			}
		}

		MemoryContextSwitchTo(fc_oldcontext);
		fc_funcctx->user_fctx = (void *) fc_state;
	}

	fc_funcctx = SRF_PERCALL_SETUP();
	fc_state = (OkeysState *) fc_funcctx->user_fctx;

	if (fc_state->sent_count < fc_state->result_count)
	{
		char	   *fc_nxt = fc_state->result[fc_state->sent_count++];

		SRF_RETURN_NEXT(fc_funcctx, CStringGetTextDatum(fc_nxt));
	}

	SRF_RETURN_DONE(fc_funcctx);
}

/*
 * 报告 JSON 错误。
 */
void json_ereport_error(JsonParseErrorType fc_error, JsonLexContext *fc_lex)
{
	if (fc_error == JSON_UNICODE_HIGH_ESCAPE ||
		fc_error == JSON_UNICODE_CODE_POINT_ZERO)
		ereport(ERROR,
				(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
				 errmsg("unsupported Unicode escape sequence"),
				 errdetail_internal("%s", json_errdetail(fc_error, fc_lex)),
				 fc_report_json_context(fc_lex)));
	else
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("invalid input syntax for type %s", "json"),
				 errdetail_internal("%s", json_errdetail(fc_error, fc_lex)),
				 fc_report_json_context(fc_lex)));
}

/*
 * 报告一个关于虚假的 JSON 输入的 CONTEXT 行。
 *
 * lex->token_terminator 必须设置以识别我们检测到错误的地方。请注意，lex->token_start 可能为 NULL， 
 * 以防我们在文件结尾处识别到错误。
 *
 * 返回值没有实际意义，但我们将其设置为非 void，以便可以在 ereport() 内部调用。
 */
static int fc_report_json_context(JsonLexContext *fc_lex)
{
	const char *fc_context_start;
	const char *fc_context_end;
	const char *fc_line_start;
	char	   *fc_ctxt;
	int			fc_ctxtlen;
	const char *fc_prefix;
	const char *fc_suffix;

	/* 选择我们将显示的输入部分的边界 */
	fc_line_start = fc_lex->line_start;
	fc_context_start = fc_line_start;
	fc_context_end = fc_lex->token_terminator;
	Assert(fc_context_end >= fc_context_start);

	/* 前进直到我们接近 context_end */
	while (fc_context_end - fc_context_start >= 50)
	{
		/* 前进到下一个多字节字符 */
		if (IS_HIGHBIT_SET(*fc_context_start))
			fc_context_start += pg_mblen(fc_context_start);
		else
			fc_context_start++;
	}

	/*
	 * 我们添加 "..." 表示摘录并不是从行的开头开始的...
	 * 但如果我们距离行的开头只有 3 个字符，我们也可以展示整行。
	 */
	if (fc_context_start - fc_line_start <= 3)
		fc_context_start = fc_line_start;

	/* 获取数据的以 NULL 结尾的副本以便展示 */
	fc_ctxtlen = fc_context_end - fc_context_start;
	fc_ctxt = palloc(fc_ctxtlen + 1);
	memcpy(fc_ctxt, fc_context_start, fc_ctxtlen);
	fc_ctxt[fc_ctxtlen] = '\0';

	/*
	 * 显示上下文，如果不是从行的开头开始则前缀 "..."，如果不是
	 * 在行的结尾结束则后缀 "..."。
	 */
	fc_prefix = (fc_context_start > fc_line_start) ? "..." : "";
	fc_suffix = (fc_lex->token_type != JSON_TOKEN_END &&
			  fc_context_end - fc_lex->input < fc_lex->input_length &&
			  *fc_context_end != '\n' && *fc_context_end != '\r') ? "..." : "";

	return errcontext("JSON data, line %d: %s%s%s",
					  fc_lex->line_number, fc_prefix, fc_ctxt, fc_suffix);
}


Datum json_object_keys(PG_FUNCTION_ARGS)
{
	FuncCallContext *fc_funcctx;
	OkeysState *fc_state;

	if (SRF_IS_FIRSTCALL())
	{
		text	   *fc_json = PG_GETARG_TEXT_PP(0);
		JsonLexContext *fc_lex = makeJsonLexContext(fc_json, true);
		JsonSemAction *fc_sem;
		MemoryContext fc_oldcontext;

		fc_funcctx = SRF_FIRSTCALL_INIT();
		fc_oldcontext = MemoryContextSwitchTo(fc_funcctx->multi_call_memory_ctx);

		fc_state = palloc(sizeof(OkeysState));
		fc_sem = palloc0(sizeof(JsonSemAction));

		fc_state->lex = fc_lex;
		fc_state->result_size = 256;
		fc_state->result_count = 0;
		fc_state->sent_count = 0;
		fc_state->result = palloc(256 * sizeof(char *));

		fc_sem->semstate = (void *) fc_state;
		fc_sem->array_start = fc_okeys_array_start;
		fc_sem->scalar = fc_okeys_scalar;
		fc_sem->object_field_start = fc_okeys_object_field_start;
		/* 其余部分都是 NULL，感谢上面的 palloc0 */

		pg_parse_json_or_ereport(fc_lex, fc_sem);
		/* keys 现在在 state->result 中 */

		pfree(fc_lex->strval->data);
		pfree(fc_lex->strval);
		pfree(fc_lex);
		pfree(fc_sem);

		MemoryContextSwitchTo(fc_oldcontext);
		fc_funcctx->user_fctx = (void *) fc_state;
	}

	fc_funcctx = SRF_PERCALL_SETUP();
	fc_state = (OkeysState *) fc_funcctx->user_fctx;

	if (fc_state->sent_count < fc_state->result_count)
	{
		char	   *fc_nxt = fc_state->result[fc_state->sent_count++];

		SRF_RETURN_NEXT(fc_funcctx, CStringGetTextDatum(fc_nxt));
	}

	SRF_RETURN_DONE(fc_funcctx);
}

static void fc_okeys_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	OkeysState *fc__state = (OkeysState *) fc_state;

	/* 只为顶层对象收集键 */
	if (fc__state->lex->lex_level != 1)
		return;

	/* 如有必要，增大结果数组 */
	if (fc__state->result_count >= fc__state->result_size)
	{
		fc__state->result_size *= 2;
		fc__state->result = (char **)
			repalloc(fc__state->result, sizeof(char *) * fc__state->result_size);
	}

	/* 保存字段名称的副本 */
	fc__state->result[fc__state->result_count++] = pstrdup(fc_fname);
}

static void fc_okeys_array_start(void *fc_state)
{
	OkeysState *fc__state = (OkeysState *) fc_state;

	/* 顶层必须是一个 json 对象 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on an array",
						"json_object_keys")));
}

static void fc_okeys_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	OkeysState *fc__state = (OkeysState *) fc_state;

	/* 顶层必须是一个 json 对象 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on a scalar",
						"json_object_keys")));
}

/*
 * json 和 jsonb 获取函数
 * 这些实现了 -> ->> #> 和 #>> 操作符
 * 以及 json{b?}_extract_path*(json, text, ...) 函数
 */


Datum json_object_field(PG_FUNCTION_ARGS)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	text	   *fc_fname = PG_GETARG_TEXT_PP(1);
	char	   *fc_fnamestr = text_to_cstring(fc_fname);
	text	   *fc_result;

	fc_result = get_worker(fc_json, &fc_fnamestr, NULL, 1, false);

	if (fc_result != NULL)
		PG_RETURN_TEXT_P(fc_result);
	else
		PG_RETURN_NULL();
}

Datum jsonb_object_field(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	text	   *fc_key = PG_GETARG_TEXT_PP(1);
	JsonbValue *fc_v;
	JsonbValue	fc_vbuf;

	if (!JB_ROOT_IS_OBJECT(fc_jb))
		PG_RETURN_NULL();

	fc_v = getKeyJsonValueFromContainer(&fc_jb->root,
									 VARDATA_ANY(fc_key),
									 VARSIZE_ANY_EXHDR(fc_key),
									 &fc_vbuf);

	if (fc_v != NULL)
		PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_v));

	PG_RETURN_NULL();
}

Datum json_object_field_text(PG_FUNCTION_ARGS)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	text	   *fc_fname = PG_GETARG_TEXT_PP(1);
	char	   *fc_fnamestr = text_to_cstring(fc_fname);
	text	   *fc_result;

	fc_result = get_worker(fc_json, &fc_fnamestr, NULL, 1, true);

	if (fc_result != NULL)
		PG_RETURN_TEXT_P(fc_result);
	else
		PG_RETURN_NULL();
}

Datum jsonb_object_field_text(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	text	   *fc_key = PG_GETARG_TEXT_PP(1);
	JsonbValue *fc_v;
	JsonbValue	fc_vbuf;

	if (!JB_ROOT_IS_OBJECT(fc_jb))
		PG_RETURN_NULL();

	fc_v = getKeyJsonValueFromContainer(&fc_jb->root,
									 VARDATA_ANY(fc_key),
									 VARSIZE_ANY_EXHDR(fc_key),
									 &fc_vbuf);

	if (fc_v != NULL && fc_v->type != jbvNull)
		PG_RETURN_TEXT_P(fc_JsonbValueAsText(fc_v));

	PG_RETURN_NULL();
}

Datum json_array_element(PG_FUNCTION_ARGS)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	int			fc_element = PG_GETARG_INT32(1);
	text	   *fc_result;

	fc_result = get_worker(fc_json, NULL, &fc_element, 1, false);

	if (fc_result != NULL)
		PG_RETURN_TEXT_P(fc_result);
	else
		PG_RETURN_NULL();
}

Datum jsonb_array_element(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	int			fc_element = PG_GETARG_INT32(1);
	JsonbValue *fc_v;

	if (!JB_ROOT_IS_ARRAY(fc_jb))
		PG_RETURN_NULL();

	/* 处理负下标 */
	if (fc_element < 0)
	{
		uint32		fc_nelements = JB_ROOT_COUNT(fc_jb);

		if (-fc_element > fc_nelements)
			PG_RETURN_NULL();
		else
			fc_element += fc_nelements;
	}

	fc_v = getIthJsonbValueFromContainer(&fc_jb->root, fc_element);
	if (fc_v != NULL)
		PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_v));

	PG_RETURN_NULL();
}

Datum json_array_element_text(PG_FUNCTION_ARGS)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	int			fc_element = PG_GETARG_INT32(1);
	text	   *fc_result;

	fc_result = get_worker(fc_json, NULL, &fc_element, 1, true);

	if (fc_result != NULL)
		PG_RETURN_TEXT_P(fc_result);
	else
		PG_RETURN_NULL();
}

Datum jsonb_array_element_text(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	int			fc_element = PG_GETARG_INT32(1);
	JsonbValue *fc_v;

	if (!JB_ROOT_IS_ARRAY(fc_jb))
		PG_RETURN_NULL();

	/* 处理负下标 */
	if (fc_element < 0)
	{
		uint32		fc_nelements = JB_ROOT_COUNT(fc_jb);

		if (-fc_element > fc_nelements)
			PG_RETURN_NULL();
		else
			fc_element += fc_nelements;
	}

	fc_v = getIthJsonbValueFromContainer(&fc_jb->root, fc_element);

	if (fc_v != NULL && fc_v->type != jbvNull)
		PG_RETURN_TEXT_P(fc_JsonbValueAsText(fc_v));

	PG_RETURN_NULL();
}

Datum json_extract_path(PG_FUNCTION_ARGS)
{
	return get_path_all(fcinfo, false);
}

Datum json_extract_path_text(PG_FUNCTION_ARGS)
{
	return get_path_all(fcinfo, true);
}

/*
 * 提取路径函数的通用例程
 */
static Datum get_path_all(FunctionCallInfo fcinfo, bool fc_as_text)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	ArrayType  *fc_path = PG_GETARG_ARRAYTYPE_P(1);
	text	   *fc_result;
	Datum	   *fc_pathtext;
	bool	   *fc_pathnulls;
	int			fc_npath;
	char	  **fc_tpath;
	int		   *fc_ipath;
	int			fc_i;

	/*
	 * 如果数组包含任何 null 元素，则返回 NULL，理由是如果
	 * 在嵌套系列的 -> 操作符中任何 RHS 值为 NULL，您将得到 NULL。
	 * (注意：因为我们也为如无此字段的错误情况返回 NULL，
	 * 所以这在数组的其余部分内容无论如何都是正确的。)
	 */
	if (array_contains_nulls(fc_path))
		PG_RETURN_NULL();

	deconstruct_array(fc_path, TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_pathtext, &fc_pathnulls, &fc_npath);

	fc_tpath = palloc(fc_npath * sizeof(char *));
	fc_ipath = palloc(fc_npath * sizeof(int));

	for (fc_i = 0; fc_i < fc_npath; fc_i++)
	{
		Assert(!fc_pathnulls[fc_i]);
		fc_tpath[fc_i] = TextDatumGetCString(fc_pathtext[fc_i]);

		/*
		 * 在这个阶段我们不知道文档的结构是什么，
		 * 因此将路径中可以转换为整数的任何东西都转换为整数，
		 * 并将所有其他整数设置为 INT_MIN，这将永远无法匹配。
		 */
		if (*fc_tpath[fc_i] != '\0')
		{
			int			fc_ind;
			char	   *fc_endptr;

			errno = 0;
			fc_ind = strtoint(fc_tpath[fc_i], &fc_endptr, 10);
			if (fc_endptr == fc_tpath[fc_i] || *fc_endptr != '\0' || errno != 0)
				fc_ipath[fc_i] = INT_MIN;
			else
				fc_ipath[fc_i] = fc_ind;
		}
		else
			fc_ipath[fc_i] = INT_MIN;
	}

	fc_result = get_worker(fc_json, fc_tpath, fc_ipath, fc_npath, fc_as_text);

	if (fc_result != NULL)
		PG_RETURN_TEXT_P(fc_result);
	else
		PG_RETURN_NULL();
}

/*
 * get_worker
 *
 * 所有 json 获取函数的通用工作程序
 *
 * json: JSON 对象（文本形式）
 * tpath[]: 要提取的字段名称
 * ipath[]: 要提取的数组下标（零基），接受负数
 * npath: tpath[] 和/或 ipath[] 的长度
 * normalize_results: true 用于解除转义字符串和 null 标量
 *
 * tpath 可以为 NULL，或者任何一个 tpath[] 条目可以为 NULL，
 * 如果该嵌套级别不需要匹配对象字段。同样，ipath 可以为 NULL，
 * 或者任何一个 ipath[] 条目可以为 INT_MIN，
 * 如果该嵌套级别不需要匹配数组元素（由于 MaxAllocSize 限制，json 数据
 * 永远不会大到有 -INT_MIN 个元素）。
 */
static text * get_worker(text *fc_json,
		   char **fc_tpath,
		   int *fc_ipath,
		   int fc_npath,
		   bool fc_normalize_results)
{
	JsonLexContext *fc_lex = makeJsonLexContext(fc_json, true);
	JsonSemAction *fc_sem = palloc0(sizeof(JsonSemAction));
	GetState   *fc_state = palloc0(sizeof(GetState));

	Assert(fc_npath >= 0);

	fc_state->lex = fc_lex;
	/* 是不是 "_as_text" 变体？ */
	fc_state->normalize_results = fc_normalize_results;
	fc_state->npath = fc_npath;
	fc_state->path_names = fc_tpath;
	fc_state->path_indexes = fc_ipath;
	fc_state->pathok = palloc0(sizeof(bool) * fc_npath);
	fc_state->array_cur_index = palloc(sizeof(int) * fc_npath);

	if (fc_npath > 0)
		fc_state->pathok[0] = true;

	fc_sem->semstate = (void *) fc_state;

	/*
	 * 并不是所有的变体都需要所有的语义例程。
	 * 仅设置实际需要以最大化效率的例程。
	 */
	fc_sem->scalar = get_scalar;
	if (fc_npath == 0)
	{
		fc_sem->object_start = get_object_start;
		fc_sem->object_end = get_object_end;
		fc_sem->array_start = get_array_start;
		fc_sem->array_end = get_array_end;
	}
	if (fc_tpath != NULL)
	{
		fc_sem->object_field_start = get_object_field_start;
		fc_sem->object_field_end = get_object_field_end;
	}
	if (fc_ipath != NULL)
	{
		fc_sem->array_start = get_array_start;
		fc_sem->array_element_start = get_array_element_start;
		fc_sem->array_element_end = get_array_element_end;
	}

	pg_parse_json_or_ereport(fc_lex, fc_sem);

	return fc_state->tresult;
}

static void get_object_start(void *fc_state)
{
	GetState   *fc__state = (GetState *) fc_state;
	int			fc_lex_level = fc__state->lex->lex_level;

	if (fc_lex_level == 0 && fc__state->npath == 0)
	{
		/*
		 * 特殊情况：我们应该匹配整个对象。
		 * 我们只在最外层需要这个，因为在嵌套层次中，匹配
		 * 将由外部字段或数组元素回调开始。
		 */
		fc__state->result_start = fc__state->lex->token_start;
	}
}

static void get_object_end(void *fc_state)
{
	GetState   *fc__state = (GetState *) fc_state;
	int			fc_lex_level = fc__state->lex->lex_level;

	if (fc_lex_level == 0 && fc__state->npath == 0)
	{
		/* 特殊情况：返回整个对象 */
		char	   *fc_start = fc__state->result_start;
		int			fc_len = fc__state->lex->prev_token_terminator - fc_start;

		fc__state->tresult = cstring_to_text_with_len(fc_start, fc_len);
	}
}

static void get_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	GetState   *fc__state = (GetState *) fc_state;
	bool		get_next = false;
	int			fc_lex_level = fc__state->lex->lex_level;

	if (fc_lex_level <= fc__state->npath &&
		fc__state->pathok[fc_lex_level - 1] &&
		fc__state->path_names != NULL &&
		fc__state->path_names[fc_lex_level - 1] != NULL &&
		strcmp(fc_fname, fc__state->path_names[fc_lex_level - 1]) == 0)
	{
		if (fc_lex_level < fc__state->npath)
		{
			/* 如果不在路径的结尾，则只标记路径为 OK */
			fc__state->pathok[fc_lex_level] = true;
		}
		else
		{
			/* 路径末尾，因此我们想要这个值 */
			get_next = true;
		}
	}

	if (get_next)
	{
		/* 这个对象覆盖任何先前匹配的对象 */
		fc__state->tresult = NULL;
		fc__state->result_start = NULL;

		if (fc__state->normalize_results &&
			fc__state->lex->token_type == JSON_TOKEN_STRING)
		{
			/* 对于 as_text 变体，告诉 get_scalar 为我们设置它 */
			fc__state->next_scalar = true;
		}
		else
		{
			/* 对于非 as_text 变体，仅记录 json 起始点 */
			fc__state->result_start = fc__state->lex->token_start;
		}
	}
}

static void get_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull)
{
	GetState   *fc__state = (GetState *) fc_state;
	bool		get_last = false;
	int			fc_lex_level = fc__state->lex->lex_level;

	/* 与 get_object_field_start 中的测试相同 */
	if (fc_lex_level <= fc__state->npath &&
		fc__state->pathok[fc_lex_level - 1] &&
		fc__state->path_names != NULL &&
		fc__state->path_names[fc_lex_level - 1] != NULL &&
		strcmp(fc_fname, fc__state->path_names[fc_lex_level - 1]) == 0)
	{
		if (fc_lex_level < fc__state->npath)
		{
			/* 完成此字段后重置 pathok */
			fc__state->pathok[fc_lex_level] = false;
		}
		else
		{
			/* 路径末尾，因此我们想要这个值 */
			get_last = true;
		}
	}

	/*为 as_text 标量情况，我们的工作已经完成 */
	if (get_last && fc__state->result_start != NULL)
	{
		/*
		 * 从之前提到的 json 字符串创建一个文本对象
		 * 开始到之前标记的结束（词法分析器现在在我们感兴趣的内容之后
		 * 超前）。
		 */
		if (fc_isnull && fc__state->normalize_results)
			fc__state->tresult = (text *) NULL;
		else
		{
			char	   *fc_start = fc__state->result_start;
			int			fc_len = fc__state->lex->prev_token_terminator - fc_start;

			fc__state->tresult = cstring_to_text_with_len(fc_start, fc_len);
		}

		/* 这应该是不必要的，但为了清洁起见，我们这么做： */
		fc__state->result_start = NULL;
	}
}

static void get_array_start(void *fc_state)
{
	GetState   *fc__state = (GetState *) fc_state;
	int			fc_lex_level = fc__state->lex->lex_level;

	if (fc_lex_level < fc__state->npath)
	{
		/* 初始化此数组中的元素计数 */
		fc__state->array_cur_index[fc_lex_level] = -1;

		/* INT_MIN 值保留用于表示无效下标 */
		if (fc__state->path_indexes[fc_lex_level] < 0 &&
			fc__state->path_indexes[fc_lex_level] != INT_MIN)
		{
			/* 负下标 -- 转换为正向下标 */
			JsonParseErrorType fc_error;
			int			fc_nelements;

			fc_error = json_count_array_elements(fc__state->lex, &fc_nelements);
			if (fc_error != JSON_SUCCESS)
				json_ereport_error(fc_error, fc__state->lex);

			if (-fc__state->path_indexes[fc_lex_level] <= fc_nelements)
				fc__state->path_indexes[fc_lex_level] += fc_nelements;
		}
	}
	else if (fc_lex_level == 0 && fc__state->npath == 0)
	{
		/*
		 * 特殊情况：我们应该匹配整个数组。我们只需要这个
		 * 在最外层，因为在嵌套层次，匹配将由外部字段或数组元素回调开始。
		 */
		fc__state->result_start = fc__state->lex->token_start;
	}
}

static void get_array_end(void *fc_state)
{
	GetState   *fc__state = (GetState *) fc_state;
	int			fc_lex_level = fc__state->lex->lex_level;

	if (fc_lex_level == 0 && fc__state->npath == 0)
	{
		/* 特殊情况：返回整个数组 */
		char	   *fc_start = fc__state->result_start;
		int			fc_len = fc__state->lex->prev_token_terminator - fc_start;

		fc__state->tresult = cstring_to_text_with_len(fc_start, fc_len);
	}
}

static void get_array_element_start(void *fc_state, bool fc_isnull)
{
	GetState   *fc__state = (GetState *) fc_state;
	bool		get_next = false;
	int			fc_lex_level = fc__state->lex->lex_level;

	/* 更新数组元素计数器 */
	if (fc_lex_level <= fc__state->npath)
		fc__state->array_cur_index[fc_lex_level - 1]++;

	if (fc_lex_level <= fc__state->npath &&
		fc__state->pathok[fc_lex_level - 1] &&
		fc__state->path_indexes != NULL &&
		fc__state->array_cur_index[fc_lex_level - 1] == fc__state->path_indexes[fc_lex_level - 1])
	{
		if (fc_lex_level < fc__state->npath)
		{
			/* 如果不在路径的结尾，则只标记路径为 OK */
			fc__state->pathok[fc_lex_level] = true;
		}
		else
		{
			/* 路径末尾，因此我们想要这个值 */
			get_next = true;
		}
	}

	/* 与对象相同的逻辑 */
	if (get_next)
	{
		fc__state->tresult = NULL;
		fc__state->result_start = NULL;

		if (fc__state->normalize_results &&
			fc__state->lex->token_type == JSON_TOKEN_STRING)
		{
			fc__state->next_scalar = true;
		}
		else
		{
			fc__state->result_start = fc__state->lex->token_start;
		}
	}
}

static void get_array_element_end(void *fc_state, bool fc_isnull)
{
	GetState   *fc__state = (GetState *) fc_state;
	bool		get_last = false;
	int			fc_lex_level = fc__state->lex->lex_level;

	/* 与 get_array_element_start 中的测试相同 */
	if (fc_lex_level <= fc__state->npath &&
		fc__state->pathok[fc_lex_level - 1] &&
		fc__state->path_indexes != NULL &&
		fc__state->array_cur_index[fc_lex_level - 1] == fc__state->path_indexes[fc_lex_level - 1])
	{
		if (fc_lex_level < fc__state->npath)
		{
			/* 此元素处理完毕，因此重置 pathok */
			fc__state->pathok[fc_lex_level] = false;
		}
		else
		{
			/* 路径末尾，因此我们想要这个值 */
			get_last = true;
		}
	}

	/* 与对象相同的逻辑 */
	if (get_last && fc__state->result_start != NULL)
	{
		if (fc_isnull && fc__state->normalize_results)
			fc__state->tresult = (text *) NULL;
		else
		{
			char	   *fc_start = fc__state->result_start;
			int			fc_len = fc__state->lex->prev_token_terminator - fc_start;

			fc__state->tresult = cstring_to_text_with_len(fc_start, fc_len);
		}

		fc__state->result_start = NULL;
	}
}

static void get_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	GetState   *fc__state = (GetState *) fc_state;
	int			fc_lex_level = fc__state->lex->lex_level;

	/* 检查整个对象匹配 */
	if (fc_lex_level == 0 && fc__state->npath == 0)
	{
		if (fc__state->normalize_results && fc_tokentype == JSON_TOKEN_STRING)
		{
			/* 我们想要去转义的字符串 */
			fc__state->next_scalar = true;
		}
		else if (fc__state->normalize_results && fc_tokentype == JSON_TOKEN_NULL)
		{
			fc__state->tresult = (text *) NULL;
		}
		else
		{
			/*
			 * 这有点奇怪：我们将抑制标量标记后的空格，
			 * 但不抑制它之前的空格。可能不值得
			 * 自己进行换行跳过以避免这一点。
			 */
			char	   *fc_start = fc__state->lex->input;
			int			fc_len = fc__state->lex->prev_token_terminator - fc_start;

			fc__state->tresult = cstring_to_text_with_len(fc_start, fc_len);
		}
	}

	if (fc__state->next_scalar)
	{
		/* 需要去转义的文本值，因此提供它 */
		fc__state->tresult = cstring_to_text(fc_token);
		/* 确保下一次调用 get_scalar 不会覆盖它 */
		fc__state->next_scalar = false;
	}
}

Datum jsonb_extract_path(PG_FUNCTION_ARGS)
{
	return get_jsonb_path_all(fcinfo, false);
}

Datum jsonb_extract_path_text(PG_FUNCTION_ARGS)
{
	return get_jsonb_path_all(fcinfo, true);
}

static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool fc_as_text)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	ArrayType  *fc_path = PG_GETARG_ARRAYTYPE_P(1);
	Datum	   *fc_pathtext;
	bool	   *fc_pathnulls;
	bool		fc_isnull;
	int			fc_npath;
	Datum		fc_res;

	/*
	 * 如果数组包含任何 null 元素，则返回 NULL，理由是如果
	 * 在嵌套系列的 -> 操作符中任何 RHS 值为 NULL，您将得到 NULL。
	 * (注意：因为我们也为如无此字段的错误情况返回 NULL，
	 * 所以这在数组的其余部分内容无论如何都是正确的。)
	 */
	if (array_contains_nulls(fc_path))
		PG_RETURN_NULL();

	deconstruct_array(fc_path, TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_pathtext, &fc_pathnulls, &fc_npath);

	fc_res = jsonb_get_element(fc_jb, fc_pathtext, fc_npath, &fc_isnull, fc_as_text);

	if (fc_isnull)
		PG_RETURN_NULL();
	else
		PG_RETURN_DATUM(fc_res);
}

Datum jsonb_get_element(Jsonb *fc_jb, Datum *fc_path, int fc_npath, bool *fc_isnull, bool fc_as_text)
{
	JsonbContainer *fc_container = &fc_jb->root;
	JsonbValue *fc_jbvp = NULL;
	int			fc_i;
	bool		fc_have_object = false,
				fc_have_array = false;

	*fc_isnull = false;

	/* 确定我们在顶层是否有对象、数组或标量 */
	if (JB_ROOT_IS_OBJECT(fc_jb))
		fc_have_object = true;
	else if (JB_ROOT_IS_ARRAY(fc_jb) && !JB_ROOT_IS_SCALAR(fc_jb))
		fc_have_array = true;
	else
	{
		Assert(JB_ROOT_IS_ARRAY(fc_jb) && JB_ROOT_IS_SCALAR(fc_jb));
		/* 提取标量值，如果这是我们将要返回的 */
		if (fc_npath <= 0)
			fc_jbvp = getIthJsonbValueFromContainer(fc_container, 0);
	}

	/*
	 * 如果数组是空的，返回整个 LHS 对象，理由是
	 * 我们应该进行零字段或元素提取。对于
	 * 非标量的情况，我们可以直接返回对象，而不需要太多工作。对于
	 * 标量情况，继续处理下循环中的值。
	 * （这种不一致是因为没有简单的方法直接为根级容器生成一个
	 * JsonbValue。）
	 */
	if (fc_npath <= 0 && fc_jbvp == NULL)
	{
		if (fc_as_text)
		{
			return PointerGetDatum(cstring_to_text(JsonbToCString(NULL,
																  fc_container,
																  VARSIZE(fc_jb))));
		}
		else
		{
			/* 不是文本模式 - 只需返回 jsonb */
			PG_RETURN_JSONB_P(fc_jb);
		}
	}

	for (fc_i = 0; fc_i < fc_npath; fc_i++)
	{
		if (fc_have_object)
		{
			text	   *fc_subscr = DatumGetTextPP(fc_path[fc_i]);

			fc_jbvp = getKeyJsonValueFromContainer(fc_container,
												VARDATA_ANY(fc_subscr),
												VARSIZE_ANY_EXHDR(fc_subscr),
												NULL);
		}
		else if (fc_have_array)
		{
			int			fc_lindex;
			uint32		fc_index;
			char	   *fc_indextext = TextDatumGetCString(fc_path[fc_i]);
			char	   *fc_endptr;

			errno = 0;
			fc_lindex = strtoint(fc_indextext, &fc_endptr, 10);
			if (fc_endptr == fc_indextext || *fc_endptr != '\0' || errno != 0)
			{
				*fc_isnull = true;
				return PointerGetDatum(NULL);
			}

			if (fc_lindex >= 0)
			{
				fc_index = (uint32) fc_lindex;
			}
			else
			{
				/* 处理负下标 */
				uint32		fc_nelements;

				/* 容器必须是数组，但确保这一点 */
				if (!JsonContainerIsArray(fc_container))
					elog(ERROR, "not a jsonb array");

				fc_nelements = JsonContainerSize(fc_container);

				if (fc_lindex == INT_MIN || -fc_lindex > fc_nelements)
				{
					*fc_isnull = true;
					return PointerGetDatum(NULL);
				}
				else
					fc_index = fc_nelements + fc_lindex;
			}

			fc_jbvp = getIthJsonbValueFromContainer(fc_container, fc_index);
		}
		else
		{
			/* 标量，提取的结果为 null */
			*fc_isnull = true;
			return PointerGetDatum(NULL);
		}

		if (fc_jbvp == NULL)
		{
			*fc_isnull = true;
			return PointerGetDatum(NULL);
		}
		else if (fc_i == fc_npath - 1)
			break;

		if (fc_jbvp->type == jbvBinary)
		{
			fc_container = fc_jbvp->val.binary.data;
			fc_have_object = JsonContainerIsObject(fc_container);
			fc_have_array = JsonContainerIsArray(fc_container);
			Assert(!JsonContainerIsScalar(fc_container));
		}
		else
		{
			Assert(IsAJsonbScalar(fc_jbvp));
			fc_have_object = false;
			fc_have_array = false;
		}
	}

	if (fc_as_text)
	{
		if (fc_jbvp->type == jbvNull)
		{
			*fc_isnull = true;
			return PointerGetDatum(NULL);
		}

		return PointerGetDatum(fc_JsonbValueAsText(fc_jbvp));
	}
	else
	{
		Jsonb	   *fc_res = JsonbValueToJsonb(fc_jbvp);

		/* 不是文本模式 - 只需返回 jsonb */
		PG_RETURN_JSONB_P(fc_res);
	}
}

Datum jsonb_set_element(Jsonb *fc_jb, Datum *fc_path, int fc_path_len,
				  JsonbValue *fc_newval)
{
	JsonbValue *fc_res;
	JsonbParseState *fc_state = NULL;
	JsonbIterator *fc_it;
	bool	   *fc_path_nulls = palloc0(fc_path_len * sizeof(bool));

	if (fc_newval->type == jbvArray && fc_newval->val.array.rawScalar)
		*fc_newval = fc_newval->val.array.elems[0];

	fc_it = JsonbIteratorInit(&fc_jb->root);

	fc_res = fc_setPath(&fc_it, fc_path, fc_path_nulls, fc_path_len, &fc_state, 0, fc_newval,
				  JB_PATH_CREATE | JB_PATH_FILL_GAPS |
				  JB_PATH_CONSISTENT_POSITION);

	pfree(fc_path_nulls);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}

static void fc_push_null_elements(JsonbParseState **fc_ps, int fc_num)
{
	JsonbValue	fc_null;

	fc_null.type = jbvNull;

	while (fc_num-- > 0)
		pushJsonbValue(fc_ps, WJB_ELEM, &fc_null);
}

/*
 * 准备一个包含嵌套空对象和数组的新结构
 * 对应于指定路径，并在此路径末尾分配新值。例如，路径 [a][0][b] 
 * 和新值 1 将生成结构 {a: [{b: 1}]}.
 *
 * 调用者负责确保该路径尚不存在。
 */
static void fc_push_path(JsonbParseState **fc_st, int fc_level, Datum *fc_path_elems,
		  bool *fc_path_nulls, int fc_path_len, JsonbValue *fc_newval)
{
	/*
	 * tpath 包含在当前级别以上或等于当前级别时创建的
	 * 空 jsonb 的预期类型，可能是 jbvObject 或 jbvArray。
	 * 由于它仅包含从级别到末尾的路径切片信息，因此访问索引必须按级别进行规范化。
	 */
	enum jbvType *fc_tpath = palloc0((fc_path_len - fc_level) * sizeof(enum jbvType));
	JsonbValue	fc_newkey;

	/*
	 * 用开始标记创建链的第一部分。对于当前级别，已经创建了 WJB_BEGIN_OBJECT/WJB_BEGIN_ARRAY，
	 * 因此从下一个开始。
	 */
	for (int fc_i = fc_level + 1; fc_i < fc_path_len; fc_i++)
	{
		char	   *fc_c,
				   *fc_badp;
		int			fc_lindex;

		if (fc_path_nulls[fc_i])
			break;

		/*
		 * 尝试转换为整数以找出预期类型，对象
		 * 或数组。
		 */
		fc_c = TextDatumGetCString(fc_path_elems[fc_i]);
		errno = 0;
		fc_lindex = strtoint(fc_c, &fc_badp, 10);
		if (fc_badp == fc_c || *fc_badp != '\0' || errno != 0)
		{
			/* 文本，预期为对象 */
			fc_newkey.type = jbvString;
			fc_newkey.val.string.val = fc_c;
			fc_newkey.val.string.len = strlen(fc_c);

			(void) pushJsonbValue(fc_st, WJB_BEGIN_OBJECT, NULL);
			(void) pushJsonbValue(fc_st, WJB_KEY, &fc_newkey);

			fc_tpath[fc_i - fc_level] = jbvObject;
		}
		else
		{
			/* 整数，预期为数组 */
			(void) pushJsonbValue(fc_st, WJB_BEGIN_ARRAY, NULL);

			fc_push_null_elements(fc_st, fc_lindex);

			fc_tpath[fc_i - fc_level] = jbvArray;
		}
	}

	/* 为对象或数组插入实际值 */
	if (fc_tpath[(fc_path_len - fc_level) - 1] == jbvArray)
	{
		(void) pushJsonbValue(fc_st, WJB_ELEM, fc_newval);
	}
	else
		(void) pushJsonbValue(fc_st, WJB_VALUE, fc_newval);

	/*
	 * 关闭所有到倒数第二个级别的内容。最后一个将在
	 * 此函数外关闭。
	 */
	for (int fc_i = fc_path_len - 1; fc_i > fc_level; fc_i--)
	{
		if (fc_path_nulls[fc_i])
			break;

		if (fc_tpath[fc_i - fc_level] == jbvObject)
			(void) pushJsonbValue(fc_st, WJB_END_OBJECT, NULL);
		else
			(void) pushJsonbValue(fc_st, WJB_END_ARRAY, NULL);
	}
}

/*
 * 返回给定 JsonbValue 的文本表示。
 */
static text * fc_JsonbValueAsText(JsonbValue *fc_v)
{
	switch (fc_v->type)
	{
		case jbvNull:
			return NULL;

		case jbvBool:
			return fc_v->val.boolean ?
				cstring_to_text_with_len("true", 4) :
				cstring_to_text_with_len("false", 5);

		case jbvString:
			return cstring_to_text_with_len(fc_v->val.string.val,
											fc_v->val.string.len);

		case jbvNumeric:
			{
				Datum		fc_cstr;

				fc_cstr = DirectFunctionCall1(numeric_out,
										   PointerGetDatum(fc_v->val.numeric));

				return cstring_to_text(DatumGetCString(fc_cstr));
			}

		case jbvBinary:
			{
				StringInfoData fc_jtext;

				initStringInfo(&fc_jtext);
				(void) JsonbToCString(&fc_jtext, fc_v->val.binary.data,
									  fc_v->val.binary.len);

				return cstring_to_text_with_len(fc_jtext.data, fc_jtext.len);
			}

		default:
			elog(ERROR, "unrecognized jsonb type: %d", (int) fc_v->type);
			return NULL;
	}
}

/*
 * SQL 函数 json_array_length(json) -> int
 */
Datum json_array_length(PG_FUNCTION_ARGS)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	AlenState  *fc_state;
	JsonLexContext *fc_lex;
	JsonSemAction *fc_sem;

	fc_lex = makeJsonLexContext(fc_json, false);
	fc_state = palloc0(sizeof(AlenState));
	fc_sem = palloc0(sizeof(JsonSemAction));

	/* palloc0 为我们处理这个 */
#if 0
	state->count = 0;
#endif
	fc_state->lex = fc_lex;

	fc_sem->semstate = (void *) fc_state;
	fc_sem->object_start = fc_alen_object_start;
	fc_sem->scalar = fc_alen_scalar;
	fc_sem->array_element_start = fc_alen_array_element_start;

	pg_parse_json_or_ereport(fc_lex, fc_sem);

	PG_RETURN_INT32(fc_state->count);
}

Datum jsonb_array_length(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);

	if (JB_ROOT_IS_SCALAR(fc_jb))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot get array length of a scalar")));
	else if (!JB_ROOT_IS_ARRAY(fc_jb))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot get array length of a non-array")));

	PG_RETURN_INT32(JB_ROOT_COUNT(fc_jb));
}

/*
 * 接下来的两个检查确保 json 是一个数组（因为它不能是
 * 标量或对象）。
 */

static void fc_alen_object_start(void *fc_state)
{
	AlenState  *fc__state = (AlenState *) fc_state;

	/* json 结构检查 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot get array length of a non-array")));
}

static void fc_alen_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	AlenState  *fc__state = (AlenState *) fc_state;

	/* json 结构检查 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot get array length of a scalar")));
}

static void fc_alen_array_element_start(void *fc_state, bool fc_isnull)
{
	AlenState  *fc__state = (AlenState *) fc_state;

	/* 只是计算所有一级元素的数量 */
	if (fc__state->lex->lex_level == 1)
		fc__state->count++;
}

/*
 * SQL 函数 json_each 和 json_each_text
 *
 * 将 json 对象解构为键值对。
 *
 * 与 json_object_keys() 不同，这些 SRFs 在物化模式中操作，
 * 在过程中将结果存储到 Tuplestore 对象中。
 * 元组的构建使用一个临时内存上下文，
 * 在每个元组构建完成后清除。
 */
Datum json_each(PG_FUNCTION_ARGS)
{
	return fc_each_worker(fcinfo, false);
}

Datum jsonb_each(PG_FUNCTION_ARGS)
{
	return fc_each_worker_jsonb(fcinfo, "jsonb_each", false);
}

Datum json_each_text(PG_FUNCTION_ARGS)
{
	return fc_each_worker(fcinfo, true);
}

Datum jsonb_each_text(PG_FUNCTION_ARGS)
{
	return fc_each_worker_jsonb(fcinfo, "jsonb_each_text", true);
}

static Datum fc_each_worker_jsonb(FunctionCallInfo fcinfo, const char *fc_funcname, bool fc_as_text)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	ReturnSetInfo *fc_rsi;
	MemoryContext fc_old_cxt,
				fc_tmp_cxt;
	bool		fc_skipNested = false;
	JsonbIterator *fc_it;
	JsonbValue	fc_v;
	JsonbIteratorToken fc_r;

	if (!JB_ROOT_IS_OBJECT(fc_jb))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on a non-object",
						fc_funcname)));

	fc_rsi = (ReturnSetInfo *) fcinfo->resultinfo;
	InitMaterializedSRF(fcinfo, MAT_SRF_BLESS);

	fc_tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
									"jsonb_each temporary cxt",
									ALLOCSET_DEFAULT_SIZES);

	fc_it = JsonbIteratorInit(&fc_jb->root);

	while ((fc_r = JsonbIteratorNext(&fc_it, &fc_v, fc_skipNested)) != WJB_DONE)
	{
		fc_skipNested = true;

		if (fc_r == WJB_KEY)
		{
			text	   *fc_key;
			Datum		fc_values[2];
			bool		fc_nulls[2] = {false, false};

			/* 使用临时上下文，以便在每个元组处理完成后进行清理 */
			fc_old_cxt = MemoryContextSwitchTo(fc_tmp_cxt);

			fc_key = cstring_to_text_with_len(fc_v.val.string.val, fc_v.val.string.len);

			/*
			 * 迭代器获取的下一个内容应该是值，无论其形状如何。
			 */
			fc_r = JsonbIteratorNext(&fc_it, &fc_v, fc_skipNested);
			Assert(fc_r != WJB_DONE);

			fc_values[0] = PointerGetDatum(fc_key);

			if (fc_as_text)
			{
				if (fc_v.type == jbvNull)
				{
					/* 在文本模式下，json null 是 sql null */
					fc_nulls[1] = true;
					fc_values[1] = (Datum) NULL;
				}
				else
					fc_values[1] = PointerGetDatum(fc_JsonbValueAsText(&fc_v));
			}
			else
			{
				/* 在非文本模式中，仅返回 Jsonb */
				Jsonb	   *fc_val = JsonbValueToJsonb(&fc_v);

				fc_values[1] = PointerGetDatum(fc_val);
			}

			tuplestore_putvalues(fc_rsi->setResult, fc_rsi->setDesc, fc_values, fc_nulls);

			/* 清理并切换回去 */
			MemoryContextSwitchTo(fc_old_cxt);
			MemoryContextReset(fc_tmp_cxt);
		}
	}

	MemoryContextDelete(fc_tmp_cxt);

	PG_RETURN_NULL();
}


static Datum fc_each_worker(FunctionCallInfo fcinfo, bool fc_as_text)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	JsonLexContext *fc_lex;
	JsonSemAction *fc_sem;
	ReturnSetInfo *fc_rsi;
	EachState  *fc_state;

	fc_lex = makeJsonLexContext(fc_json, true);
	fc_state = palloc0(sizeof(EachState));
	fc_sem = palloc0(sizeof(JsonSemAction));

	fc_rsi = (ReturnSetInfo *) fcinfo->resultinfo;

	InitMaterializedSRF(fcinfo, MAT_SRF_BLESS);
	fc_state->tuple_store = fc_rsi->setResult;
	fc_state->ret_tdesc = fc_rsi->setDesc;

	fc_sem->semstate = (void *) fc_state;
	fc_sem->array_start = fc_each_array_start;
	fc_sem->scalar = fc_each_scalar;
	fc_sem->object_field_start = fc_each_object_field_start;
	fc_sem->object_field_end = fc_each_object_field_end;

	fc_state->normalize_results = fc_as_text;
	fc_state->next_scalar = false;
	fc_state->lex = fc_lex;
	fc_state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
										   "json_each temporary cxt",
										   ALLOCSET_DEFAULT_SIZES);

	pg_parse_json_or_ereport(fc_lex, fc_sem);

	MemoryContextDelete(fc_state->tmp_cxt);

	PG_RETURN_NULL();
}


static void fc_each_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	EachState  *fc__state = (EachState *) fc_state;

	/* 保存一个指向值开始位置的指针 */
	if (fc__state->lex->lex_level == 1)
	{
		/*
		 * next_scalar 将在 object_field_end 处理程序中重置，
		 * 由于我们知道值是标量，因此在向下递归时不会有
		 * 危险。
		 */
		if (fc__state->normalize_results && fc__state->lex->token_type == JSON_TOKEN_STRING)
			fc__state->next_scalar = true;
		else
			fc__state->result_start = fc__state->lex->token_start;
	}
}

static void fc_each_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull)
{
	EachState  *fc__state = (EachState *) fc_state;
	MemoryContext fc_old_cxt;
	int			fc_len;
	text	   *fc_val;
	HeapTuple	fc_tuple;
	Datum		fc_values[2];
	bool		fc_nulls[2] = {false, false};

	/* 跳过嵌套对象 */
	if (fc__state->lex->lex_level != 1)
		return;

	/* 使用 tmp 上下文，以便在每个元组完成后进行清理 */
	fc_old_cxt = MemoryContextSwitchTo(fc__state->tmp_cxt);

	fc_values[0] = CStringGetTextDatum(fc_fname);

	if (fc_isnull && fc__state->normalize_results)
	{
		fc_nulls[1] = true;
		fc_values[1] = (Datum) 0;
	}
	else if (fc__state->next_scalar)
	{
		fc_values[1] = CStringGetTextDatum(fc__state->normalized_scalar);
		fc__state->next_scalar = false;
	}
	else
	{
		fc_len = fc__state->lex->prev_token_terminator - fc__state->result_start;
		fc_val = cstring_to_text_with_len(fc__state->result_start, fc_len);
		fc_values[1] = PointerGetDatum(fc_val);
	}

	fc_tuple = heap_form_tuple(fc__state->ret_tdesc, fc_values, fc_nulls);

	tuplestore_puttuple(fc__state->tuple_store, fc_tuple);

	/* 清理并切换回去 */
	MemoryContextSwitchTo(fc_old_cxt);
	MemoryContextReset(fc__state->tmp_cxt);
}

static void fc_each_array_start(void *fc_state)
{
	EachState  *fc__state = (EachState *) fc_state;

	/* json 结构检查 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot deconstruct an array as an object")));
}

static void fc_each_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	EachState  *fc__state = (EachState *) fc_state;

	/* json 结构检查 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot deconstruct a scalar")));

	/* 如果需要，提供去转义的值 */
	if (fc__state->next_scalar)
		fc__state->normalized_scalar = fc_token;
}

/*
 * SQL 函数 json_array_elements 和 json_array_elements_text
 *
 * 从 json 数组中获取元素
 *
 * 很多此类处理与 json_each* 函数相似
 */

Datum jsonb_array_elements(PG_FUNCTION_ARGS)
{
	return fc_elements_worker_jsonb(fcinfo, "jsonb_array_elements", false);
}

Datum jsonb_array_elements_text(PG_FUNCTION_ARGS)
{
	return fc_elements_worker_jsonb(fcinfo, "jsonb_array_elements_text", true);
}

static Datum fc_elements_worker_jsonb(FunctionCallInfo fcinfo, const char *fc_funcname,
					  bool fc_as_text)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	ReturnSetInfo *fc_rsi;
	MemoryContext fc_old_cxt,
				fc_tmp_cxt;
	bool		fc_skipNested = false;
	JsonbIterator *fc_it;
	JsonbValue	fc_v;
	JsonbIteratorToken fc_r;

	if (JB_ROOT_IS_SCALAR(fc_jb))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot extract elements from a scalar")));
	else if (!JB_ROOT_IS_ARRAY(fc_jb))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot extract elements from an object")));

	fc_rsi = (ReturnSetInfo *) fcinfo->resultinfo;

	InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC | MAT_SRF_BLESS);

	fc_tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
									"jsonb_array_elements temporary cxt",
									ALLOCSET_DEFAULT_SIZES);

	fc_it = JsonbIteratorInit(&fc_jb->root);

	while ((fc_r = JsonbIteratorNext(&fc_it, &fc_v, fc_skipNested)) != WJB_DONE)
	{
		fc_skipNested = true;

		if (fc_r == WJB_ELEM)
		{
			Datum		fc_values[1];
			bool		fc_nulls[1] = {false};

			/* 使用 tmp 上下文，以便在每个元组完成后进行清理 */
			fc_old_cxt = MemoryContextSwitchTo(fc_tmp_cxt);

			if (fc_as_text)
			{
				if (fc_v.type == jbvNull)
				{
					/* 在文本模式下，json null 是 sql null */
					fc_nulls[0] = true;
					fc_values[0] = (Datum) NULL;
				}
				else
					fc_values[0] = PointerGetDatum(fc_JsonbValueAsText(&fc_v));
			}
			else
			{
				/* 在非文本模式中，仅返回 Jsonb */
				Jsonb	   *fc_val = JsonbValueToJsonb(&fc_v);

				fc_values[0] = PointerGetDatum(fc_val);
			}

			tuplestore_putvalues(fc_rsi->setResult, fc_rsi->setDesc, fc_values, fc_nulls);

			/* 清理并切换回去 */
			MemoryContextSwitchTo(fc_old_cxt);
			MemoryContextReset(fc_tmp_cxt);
		}
	}

	MemoryContextDelete(fc_tmp_cxt);

	PG_RETURN_NULL();
}

Datum json_array_elements(PG_FUNCTION_ARGS)
{
	return fc_elements_worker(fcinfo, "json_array_elements", false);
}

Datum json_array_elements_text(PG_FUNCTION_ARGS)
{
	return fc_elements_worker(fcinfo, "json_array_elements_text", true);
}

static Datum fc_elements_worker(FunctionCallInfo fcinfo, const char *fc_funcname, bool fc_as_text)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);

	/* 仅在 as_text 时需要转义字符串的元素 */
	JsonLexContext *fc_lex = makeJsonLexContext(fc_json, fc_as_text);
	JsonSemAction *fc_sem;
	ReturnSetInfo *fc_rsi;
	ElementsState *fc_state;

	fc_state = palloc0(sizeof(ElementsState));
	fc_sem = palloc0(sizeof(JsonSemAction));

	InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC | MAT_SRF_BLESS);
	fc_rsi = (ReturnSetInfo *) fcinfo->resultinfo;
	fc_state->tuple_store = fc_rsi->setResult;
	fc_state->ret_tdesc = fc_rsi->setDesc;

	fc_sem->semstate = (void *) fc_state;
	fc_sem->object_start = fc_elements_object_start;
	fc_sem->scalar = fc_elements_scalar;
	fc_sem->array_element_start = fc_elements_array_element_start;
	fc_sem->array_element_end = fc_elements_array_element_end;

	fc_state->function_name = fc_funcname;
	fc_state->normalize_results = fc_as_text;
	fc_state->next_scalar = false;
	fc_state->lex = fc_lex;
	fc_state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
										   "json_array_elements temporary cxt",
										   ALLOCSET_DEFAULT_SIZES);

	pg_parse_json_or_ereport(fc_lex, fc_sem);

	MemoryContextDelete(fc_state->tmp_cxt);

	PG_RETURN_NULL();
}

static void fc_elements_array_element_start(void *fc_state, bool fc_isnull)
{
	ElementsState *fc__state = (ElementsState *) fc_state;

	/* 保存一个指向值开始位置的指针 */
	if (fc__state->lex->lex_level == 1)
	{
		/*
		 * next_scalar 将在 array_element_end 处理程序中重置，
		 * 由于我们知道值是标量，因此在向下递归时不会有
		 * 危险。
		 */
		if (fc__state->normalize_results && fc__state->lex->token_type == JSON_TOKEN_STRING)
			fc__state->next_scalar = true;
		else
			fc__state->result_start = fc__state->lex->token_start;
	}
}

static void fc_elements_array_element_end(void *fc_state, bool fc_isnull)
{
	ElementsState *fc__state = (ElementsState *) fc_state;
	MemoryContext fc_old_cxt;
	int			fc_len;
	text	   *fc_val;
	HeapTuple	fc_tuple;
	Datum		fc_values[1];
	bool		fc_nulls[1] = {false};

	/* 跳过嵌套对象 */
	if (fc__state->lex->lex_level != 1)
		return;

	/* 使用 tmp 上下文，以便在每个元组完成后进行清理 */
	fc_old_cxt = MemoryContextSwitchTo(fc__state->tmp_cxt);

	if (fc_isnull && fc__state->normalize_results)
	{
		fc_nulls[0] = true;
		fc_values[0] = (Datum) NULL;
	}
	else if (fc__state->next_scalar)
	{
		fc_values[0] = CStringGetTextDatum(fc__state->normalized_scalar);
		fc__state->next_scalar = false;
	}
	else
	{
		fc_len = fc__state->lex->prev_token_terminator - fc__state->result_start;
		fc_val = cstring_to_text_with_len(fc__state->result_start, fc_len);
		fc_values[0] = PointerGetDatum(fc_val);
	}

	fc_tuple = heap_form_tuple(fc__state->ret_tdesc, fc_values, fc_nulls);

	tuplestore_puttuple(fc__state->tuple_store, fc_tuple);

	/* 清理并切换回去 */
	MemoryContextSwitchTo(fc_old_cxt);
	MemoryContextReset(fc__state->tmp_cxt);
}

static void fc_elements_object_start(void *fc_state)
{
	ElementsState *fc__state = (ElementsState *) fc_state;

	/* json 结构检查 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on a non-array",
						fc__state->function_name)));
}

static void fc_elements_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	ElementsState *fc__state = (ElementsState *) fc_state;

	/* json 结构检查 */
	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on a scalar",
						fc__state->function_name)));

	/* 如果需要，提供去转义的值 */
	if (fc__state->next_scalar)
		fc__state->normalized_scalar = fc_token;
}

/*
 * SQL 函数 json_populate_record
 *
 * 从参数 json 中设置记录中的字段
 *
 * 代码无耻地改编自 hstore 的 populate_record，
 * 而 hstore 部分改编自 record_out。
 *
 * json 被解构为一个哈希表，其中记录中的每个
 * 字段通过名称查找。对于 jsonb，
 * 我们直接从对象中获取值。
 */
Datum jsonb_populate_record(PG_FUNCTION_ARGS)
{
	return fc_populate_record_worker(fcinfo, "jsonb_populate_record",
								  false, true);
}

Datum jsonb_to_record(PG_FUNCTION_ARGS)
{
	return fc_populate_record_worker(fcinfo, "jsonb_to_record",
								  false, false);
}

Datum json_populate_record(PG_FUNCTION_ARGS)
{
	return fc_populate_record_worker(fcinfo, "json_populate_record",
								  true, true);
}

Datum json_to_record(PG_FUNCTION_ARGS)
{
	return fc_populate_record_worker(fcinfo, "json_to_record",
								  true, false);
}

/* 诊断的帮助函数 */
static void fc_populate_array_report_expected_array(PopulateArrayContext *fc_ctx, int fc_ndim)
{
	if (fc_ndim <= 0)
	{
		if (fc_ctx->colname)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("expected JSON array"),
					 errhint("See the value of key \"%s\".", fc_ctx->colname)));
		else
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("expected JSON array")));
	}
	else
	{
		StringInfoData fc_indices;
		int			fc_i;

		initStringInfo(&fc_indices);

		Assert(fc_ctx->ndims > 0 && fc_ndim < fc_ctx->ndims);

		for (fc_i = 0; fc_i < fc_ndim; fc_i++)
			appendStringInfo(&fc_indices, "[%d]", fc_ctx->sizes[fc_i]);

		if (fc_ctx->colname)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("expected JSON array"),
					 errhint("See the array element %s of key \"%s\".",
							 fc_indices.data, fc_ctx->colname)));
		else
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("expected JSON array"),
					 errhint("See the array element %s.",
							 fc_indices.data)));
	}
}

/* 当数组的维度已知时设置填充数组的维度 */
static void fc_populate_array_assign_ndims(PopulateArrayContext *fc_ctx, int fc_ndims)
{
	int			fc_i;

	Assert(fc_ctx->ndims <= 0);

	if (fc_ndims <= 0)
		fc_populate_array_report_expected_array(fc_ctx, fc_ndims);

	fc_ctx->ndims = fc_ndims;
	fc_ctx->dims = palloc(sizeof(int) * fc_ndims);
	fc_ctx->sizes = palloc0(sizeof(int) * fc_ndims);

	for (fc_i = 0; fc_i < fc_ndims; fc_i++)
		fc_ctx->dims[fc_i] = -1;		/* 维度尚未知 */
}

/* 检查填充的子数组维度 */
static void fc_populate_array_check_dimension(PopulateArrayContext *fc_ctx, int fc_ndim)
{
	int			fc_dim = fc_ctx->sizes[fc_ndim]; /* 当前维度计数器 */

	if (fc_ctx->dims[fc_ndim] == -1)
		fc_ctx->dims[fc_ndim] = fc_dim;	/* 如果尚未知，则分配维度 */
	else if (fc_ctx->dims[fc_ndim] != fc_dim)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("malformed JSON array"),
				 errdetail("Multidimensional arrays must have "
						   "sub-arrays with matching dimensions.")));

	/* 重置当前数组维度大小计数器 */
	fc_ctx->sizes[fc_ndim] = 0;

	/* 如果是嵌套子数组，则递增父维度计数器 */
	if (fc_ndim > 0)
		fc_ctx->sizes[fc_ndim - 1]++;
}

static void fc_populate_array_element(PopulateArrayContext *fc_ctx, int fc_ndim, JsValue *fc_jsv)
{
	Datum		fc_element;
	bool		fc_element_isnull;

	/* 填充数组元素 */
	fc_element = fc_populate_record_field(fc_ctx->aio->element_info,
									fc_ctx->aio->element_type,
									fc_ctx->aio->element_typmod,
									NULL, fc_ctx->mcxt, PointerGetDatum(NULL),
									fc_jsv, &fc_element_isnull);

	accumArrayResult(fc_ctx->astate, fc_element, fc_element_isnull,
					 fc_ctx->aio->element_type, fc_ctx->acxt);

	Assert(fc_ndim > 0);
	fc_ctx->sizes[fc_ndim - 1]++;		/* 递增当前维度计数器 */
}

/* json 对象开始处理器用于 populate_array_json() */
static void fc_populate_array_object_start(void *fc__state)
{
	PopulateArrayState *fc_state = (PopulateArrayState *) fc__state;
	int			fc_ndim = fc_state->lex->lex_level;

	if (fc_state->ctx->ndims <= 0)
		fc_populate_array_assign_ndims(fc_state->ctx, fc_ndim);
	else if (fc_ndim < fc_state->ctx->ndims)
		fc_populate_array_report_expected_array(fc_state->ctx, fc_ndim);
}

/* json 数组结束处理器用于 populate_array_json() */
static void fc_populate_array_array_end(void *fc__state)
{
	PopulateArrayState *fc_state = (PopulateArrayState *) fc__state;
	PopulateArrayContext *fc_ctx = fc_state->ctx;
	int			fc_ndim = fc_state->lex->lex_level;

	if (fc_ctx->ndims <= 0)
		fc_populate_array_assign_ndims(fc_ctx, fc_ndim + 1);

	if (fc_ndim < fc_ctx->ndims)
		fc_populate_array_check_dimension(fc_ctx, fc_ndim);
}

/* json 数组元素开始处理器用于 populate_array_json() */
static void fc_populate_array_element_start(void *fc__state, bool fc_isnull)
{
	PopulateArrayState *fc_state = (PopulateArrayState *) fc__state;
	int			fc_ndim = fc_state->lex->lex_level;

	if (fc_state->ctx->ndims <= 0 || fc_ndim == fc_state->ctx->ndims)
	{
		/* 记住当前数组元素开始 */
		fc_state->element_start = fc_state->lex->token_start;
		fc_state->element_type = fc_state->lex->token_type;
		fc_state->element_scalar = NULL;
	}
}

/* json 数组元素结束处理器用于 populate_array_json() */
static void fc_populate_array_element_end(void *fc__state, bool fc_isnull)
{
	PopulateArrayState *fc_state = (PopulateArrayState *) fc__state;
	PopulateArrayContext *fc_ctx = fc_state->ctx;
	int			fc_ndim = fc_state->lex->lex_level;

	Assert(fc_ctx->ndims > 0);

	if (fc_ndim == fc_ctx->ndims)
	{
		JsValue		fc_jsv;

		fc_jsv.is_json = true;
		fc_jsv.val.json.type = fc_state->element_type;

		if (fc_isnull)
		{
			Assert(fc_jsv.val.json.type == JSON_TOKEN_NULL);
			fc_jsv.val.json.str = NULL;
			fc_jsv.val.json.len = 0;
		}
		else if (fc_state->element_scalar)
		{
			fc_jsv.val.json.str = fc_state->element_scalar;
			fc_jsv.val.json.len = -1;	/* 以 null 结束 */
		}
		else
		{
			fc_jsv.val.json.str = fc_state->element_start;
			fc_jsv.val.json.len = (fc_state->lex->prev_token_terminator -
								fc_state->element_start) * sizeof(char);
		}

		fc_populate_array_element(fc_ctx, fc_ndim, &fc_jsv);
	}
}

/* json 标量处理器用于 populate_array_json() */
static void fc_populate_array_scalar(void *fc__state, char *fc_token, JsonTokenType fc_tokentype)
{
	PopulateArrayState *fc_state = (PopulateArrayState *) fc__state;
	PopulateArrayContext *fc_ctx = fc_state->ctx;
	int			fc_ndim = fc_state->lex->lex_level;

	if (fc_ctx->ndims <= 0)
		fc_populate_array_assign_ndims(fc_ctx, fc_ndim);
	else if (fc_ndim < fc_ctx->ndims)
		fc_populate_array_report_expected_array(fc_ctx, fc_ndim);

	if (fc_ndim == fc_ctx->ndims)
	{
		/* 记住标量元素令牌 */
		fc_state->element_scalar = fc_token;
		/* element_type 必须已经在 populate_array_element_start() 中设置 */
		Assert(fc_state->element_type == fc_tokentype);
	}
}

/* 解析 json 数组并填充数组 */
static void fc_populate_array_json(PopulateArrayContext *fc_ctx, char *fc_json, int fc_len)
{
	PopulateArrayState fc_state;
	JsonSemAction fc_sem;

	fc_state.lex = makeJsonLexContextCstringLen(fc_json, fc_len, GetDatabaseEncoding(), true);
	fc_state.ctx = fc_ctx;

	memset(&fc_sem, 0, sizeof(fc_sem));
	fc_sem.semstate = (void *) &fc_state;
	fc_sem.object_start = fc_populate_array_object_start;
	fc_sem.array_end = fc_populate_array_array_end;
	fc_sem.array_element_start = fc_populate_array_element_start;
	fc_sem.array_element_end = fc_populate_array_element_end;
	fc_sem.scalar = fc_populate_array_scalar;

	pg_parse_json_or_ereport(fc_state.lex, &fc_sem);

	/* 维度的数量应该已经知道 */
	Assert(fc_ctx->ndims > 0 && fc_ctx->dims);

	pfree(fc_state.lex);
}

/*
 * populate_array_dim_jsonb() -- 递归迭代 jsonb 子数组
 * 元素并使用给定的 ArrayBuildState 累积结果。
 */
static void fc_populate_array_dim_jsonb(PopulateArrayContext *fc_ctx, /* 设置 */
						 JsonbValue *fc_jbv,	/* jsonb 子数组 */
						 int fc_ndim)	/* 当前维度 */
{
	JsonbContainer *fc_jbc = fc_jbv->val.binary.data;
	JsonbIterator *fc_it;
	JsonbIteratorToken fc_tok;
	JsonbValue	fc_val;
	JsValue		fc_jsv;

	check_stack_depth();

	if (fc_jbv->type != jbvBinary || !JsonContainerIsArray(fc_jbc))
		fc_populate_array_report_expected_array(fc_ctx, fc_ndim - 1);

	Assert(!JsonContainerIsScalar(fc_jbc));

	fc_it = JsonbIteratorInit(fc_jbc);

	fc_tok = JsonbIteratorNext(&fc_it, &fc_val, true);
	Assert(fc_tok == WJB_BEGIN_ARRAY);

	fc_tok = JsonbIteratorNext(&fc_it, &fc_val, true);

	/*
	 * 如果维度的数量尚不明确，并且我们已经找到了数组的结束，
	 * 或者第一个子元素不是数组，则现在分配维度数量。
	 */
	if (fc_ctx->ndims <= 0 &&
		(fc_tok == WJB_END_ARRAY ||
		 (fc_tok == WJB_ELEM &&
		  (fc_val.type != jbvBinary ||
		   !JsonContainerIsArray(fc_val.val.binary.data)))))
		fc_populate_array_assign_ndims(fc_ctx, fc_ndim);

	fc_jsv.is_json = false;
	fc_jsv.val.jsonb = &fc_val;

	/* 处理所有数组元素 */
	while (fc_tok == WJB_ELEM)
	{
		/*
		 * 仅当维度的数量仍然未知或它不是最内部维度时递归。
		 */
		if (fc_ctx->ndims > 0 && fc_ndim >= fc_ctx->ndims)
			fc_populate_array_element(fc_ctx, fc_ndim, &fc_jsv);
		else
		{
			/* 填充子子数组 */
			fc_populate_array_dim_jsonb(fc_ctx, &fc_val, fc_ndim + 1);

			/* 维度的数量应该已经知道 */
			Assert(fc_ctx->ndims > 0 && fc_ctx->dims);

			fc_populate_array_check_dimension(fc_ctx, fc_ndim);
		}

		fc_tok = JsonbIteratorNext(&fc_it, &fc_val, true);
	}

	Assert(fc_tok == WJB_END_ARRAY);

	/* 释放迭代器，迭代直到 WJB_DONE */
	fc_tok = JsonbIteratorNext(&fc_it, &fc_val, true);
	Assert(fc_tok == WJB_DONE && !fc_it);
}

/* 从 json/jsonb 递归填充数组 */
static Datum fc_populate_array(ArrayIOData *fc_aio,
			   const char *fc_colname,
			   MemoryContext fc_mcxt,
			   JsValue *fc_jsv)
{
	PopulateArrayContext fc_ctx;
	Datum		fc_result;
	int		   *fc_lbs;
	int			fc_i;

	fc_ctx.aio = fc_aio;
	fc_ctx.mcxt = fc_mcxt;
	fc_ctx.acxt = CurrentMemoryContext;
	fc_ctx.astate = initArrayResult(fc_aio->element_type, fc_ctx.acxt, true);
	fc_ctx.colname = fc_colname;
	fc_ctx.ndims = 0;				/* 还未知 */
	fc_ctx.dims = NULL;
	fc_ctx.sizes = NULL;

	if (fc_jsv->is_json)
		fc_populate_array_json(&fc_ctx, fc_jsv->val.json.str,
							fc_jsv->val.json.len >= 0 ? fc_jsv->val.json.len
							: strlen(fc_jsv->val.json.str));
	else
	{
		fc_populate_array_dim_jsonb(&fc_ctx, fc_jsv->val.jsonb, 1);
		fc_ctx.dims[0] = fc_ctx.sizes[0];
	}

	Assert(fc_ctx.ndims > 0);

	fc_lbs = palloc(sizeof(int) * fc_ctx.ndims);

	for (fc_i = 0; fc_i < fc_ctx.ndims; fc_i++)
		fc_lbs[fc_i] = 1;

	fc_result = makeMdArrayResult(fc_ctx.astate, fc_ctx.ndims, fc_ctx.dims, fc_lbs,
							   fc_ctx.acxt, true);

	pfree(fc_ctx.dims);
	pfree(fc_ctx.sizes);
	pfree(fc_lbs);

	return fc_result;
}

static void fc_JsValueToJsObject(JsValue *fc_jsv, JsObject *fc_jso)
{
	fc_jso->is_json = fc_jsv->is_json;

	if (fc_jsv->is_json)
	{
		/* 将普通文本 json 转换为哈希表 */
		fc_jso->val.json_hash =
			get_json_object_as_hash(fc_jsv->val.json.str,
									fc_jsv->val.json.len >= 0
									? fc_jsv->val.json.len
									: strlen(fc_jsv->val.json.str),
									"populate_composite");
	}
	else
	{
		JsonbValue *fc_jbv = fc_jsv->val.jsonb;

		if (fc_jbv->type == jbvBinary &&
			JsonContainerIsObject(fc_jbv->val.binary.data))
		{
			fc_jso->val.jsonb_cont = fc_jbv->val.binary.data;
		}
		else
		{
			bool		fc_is_scalar;

			fc_is_scalar = IsAJsonbScalar(fc_jbv) ||
				(fc_jbv->type == jbvBinary &&
				 JsonContainerIsScalar(fc_jbv->val.binary.data));
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 fc_is_scalar
					 ? errmsg("cannot call %s on a scalar",
							  "populate_composite")
					 : errmsg("cannot call %s on an array",
							  "populate_composite")));
		}
	}
}

/* 获取或更新复合类型的缓存元组描述符 */
static void update_cached_tupdesc(CompositeIOData *fc_io, MemoryContext fc_mcxt)
{
	if (!fc_io->tupdesc ||
		fc_io->tupdesc->tdtypeid != fc_io->base_typid ||
		fc_io->tupdesc->tdtypmod != fc_io->base_typmod)
	{
		TupleDesc	fc_tupdesc = lookup_rowtype_tupdesc(fc_io->base_typid,
													 fc_io->base_typmod);
		MemoryContext fc_oldcxt;

		if (fc_io->tupdesc)
			FreeTupleDesc(fc_io->tupdesc);

		/* 将没有约束的元组描述符复制到缓存内存上下文 */
		fc_oldcxt = MemoryContextSwitchTo(fc_mcxt);
		fc_io->tupdesc = CreateTupleDescCopy(fc_tupdesc);
		MemoryContextSwitchTo(fc_oldcxt);

		ReleaseTupleDesc(fc_tupdesc);
	}
}

/* 从 json/jsonb 递归填充复合（行类型）值 */
static Datum fc_populate_composite(CompositeIOData *fc_io,
				   Oid fc_typid,
				   const char *fc_colname,
				   MemoryContext fc_mcxt,
				   HeapTupleHeader fc_defaultval,
				   JsValue *fc_jsv,
				   bool fc_isnull)
{
	Datum		fc_result;

	/* 获取/更新缓存元组描述符 */
	update_cached_tupdesc(fc_io, fc_mcxt);

	if (fc_isnull)
		fc_result = (Datum) 0;
	else
	{
		HeapTupleHeader fc_tuple;
		JsObject	fc_jso;

		/* 准备输入值 */
		fc_JsValueToJsObject(fc_jsv, &fc_jso);

		/* 填充结果记录元组 */
		fc_tuple = fc_populate_record(fc_io->tupdesc, &fc_io->record_io,
								fc_defaultval, fc_mcxt, &fc_jso);
		fc_result = HeapTupleHeaderGetDatum(fc_tuple);

		JsObjectFree(&fc_jso);
	}

	/*
	 * 如果它是复合类型上的域，检查域约束。 （这应该
	 * 可能重构，以便我们可以看到 TYPECAT 值，但目前，
	 * 通过将 typid 与 base_typid 进行比较来判断。）
	 */
	if (fc_typid != fc_io->base_typid && fc_typid != RECORDOID)
		domain_check(fc_result, fc_isnull, fc_typid, &fc_io->domain_info, fc_mcxt);

	return fc_result;
}

/* 从 json/jsonb 值填充非空标量值 */
static Datum fc_populate_scalar(ScalarIOData *fc_io, Oid fc_typid, int32 fc_typmod, JsValue *fc_jsv)
{
	Datum		fc_res;
	char	   *fc_str = NULL;
	char	   *fc_json = NULL;

	if (fc_jsv->is_json)
	{
		int			fc_len = fc_jsv->val.json.len;

		fc_json = fc_jsv->val.json.str;
		Assert(fc_json);
		if (fc_len >= 0)
		{
			/* 需要复制非空终止字符串 */
			fc_str = palloc(fc_len + 1 * sizeof(char));
			memcpy(fc_str, fc_json, fc_len);
			fc_str[fc_len] = '\0';
		}
		else
			fc_str = fc_json;			/* 字符串已经是空终止的 */

		/* 如果转换为 json/jsonb，则将字符串转换为有效的 JSON 字面量 */
		if ((fc_typid == JSONOID || fc_typid == JSONBOID) &&
			fc_jsv->val.json.type == JSON_TOKEN_STRING)
		{
			StringInfoData fc_buf;

			initStringInfo(&fc_buf);
			escape_json(&fc_buf, fc_str);
			/* 释放临时缓冲区 */
			if (fc_str != fc_json)
				pfree(fc_str);
			fc_str = fc_buf.data;
		}
	}
	else
	{
		JsonbValue *fc_jbv = fc_jsv->val.jsonb;

		if (fc_typid == JSONBOID)
		{
			Jsonb	   *fc_jsonb = JsonbValueToJsonb(fc_jbv); /* 直接使用 jsonb */

			return JsonbPGetDatum(fc_jsonb);
		}
		/* 将 jsonb 转换为字符串以进行 typio 调用 */
		else if (fc_typid == JSONOID && fc_jbv->type != jbvBinary)
		{
			/*
			 * 将标量 jsonb（非标量在这里作为 jbvBinary 传递）
			 * 转换为 json 字符串，保留顶层字符串的引号。
			 */
			Jsonb	   *fc_jsonb = JsonbValueToJsonb(fc_jbv);

			fc_str = JsonbToCString(NULL, &fc_jsonb->root, VARSIZE(fc_jsonb));
		}
		else if (fc_jbv->type == jbvString)	/* 引号已被去除 */
			fc_str = pnstrdup(fc_jbv->val.string.val, fc_jbv->val.string.len);
		else if (fc_jbv->type == jbvBool)
			fc_str = pstrdup(fc_jbv->val.boolean ? "true" : "false");
		else if (fc_jbv->type == jbvNumeric)
			fc_str = DatumGetCString(DirectFunctionCall1(numeric_out,
													  PointerGetDatum(fc_jbv->val.numeric)));
		else if (fc_jbv->type == jbvBinary)
			fc_str = JsonbToCString(NULL, fc_jbv->val.binary.data,
								 fc_jbv->val.binary.len);
		else
			elog(ERROR, "unrecognized jsonb type: %d", (int) fc_jbv->type);
	}

	fc_res = InputFunctionCall(&fc_io->typiofunc, fc_str, fc_io->typioparam, fc_typmod);

	/* 释放临时缓冲区 */
	if (fc_str != fc_json)
		pfree(fc_str);

	return fc_res;
}

static Datum fc_populate_domain(DomainIOData *fc_io,
				Oid fc_typid,
				const char *fc_colname,
				MemoryContext fc_mcxt,
				JsValue *fc_jsv,
				bool fc_isnull)
{
	Datum		fc_res;

	if (fc_isnull)
		fc_res = (Datum) 0;
	else
	{
		fc_res = fc_populate_record_field(fc_io->base_io,
									fc_io->base_typid, fc_io->base_typmod,
									fc_colname, fc_mcxt, PointerGetDatum(NULL),
									fc_jsv, &fc_isnull);
		Assert(!fc_isnull);
	}

	domain_check(fc_res, fc_isnull, fc_typid, &fc_io->domain_info, fc_mcxt);

	return fc_res;
}

/* 为给定类型准备列元数据缓存 */
static void fc_prepare_column_cache(ColumnIOData *fc_column,
					 Oid fc_typid,
					 int32 fc_typmod,
					 MemoryContext fc_mcxt,
					 bool fc_need_scalar)
{
	HeapTuple	fc_tup;
	Form_pg_type fc_type;

	fc_column->typid = fc_typid;
	fc_column->typmod = fc_typmod;

	fc_tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(fc_typid));
	if (!HeapTupleIsValid(fc_tup))
		elog(ERROR, "cache lookup failed for type %u", fc_typid);

	fc_type = (Form_pg_type) GETSTRUCT(fc_tup);

	if (fc_type->typtype == TYPTYPE_DOMAIN)
	{
		/*
		 * 我们可以直接移动到底部基本类型； domain_check() 将
		 * 处理所有约束的检查，适用于域的堆栈。
		 */
		Oid			fc_base_typid;
		int32		fc_base_typmod = fc_typmod;

		fc_base_typid = getBaseTypeAndTypmod(fc_typid, &fc_base_typmod);
		if (get_typtype(fc_base_typid) == TYPTYPE_COMPOSITE)
		{
			/* 复合类型的域有其自己的代码路径 */
			fc_column->typcat = TYPECAT_COMPOSITE_DOMAIN;
			fc_column->io.composite.record_io = NULL;
			fc_column->io.composite.tupdesc = NULL;
			fc_column->io.composite.base_typid = fc_base_typid;
			fc_column->io.composite.base_typmod = fc_base_typmod;
			fc_column->io.composite.domain_info = NULL;
		}
		else
		{
			/* 其他任何类型的域 */
			fc_column->typcat = TYPECAT_DOMAIN;
			fc_column->io.domain.base_typid = fc_base_typid;
			fc_column->io.domain.base_typmod = fc_base_typmod;
			fc_column->io.domain.base_io =
				MemoryContextAllocZero(fc_mcxt, sizeof(ColumnIOData));
			fc_column->io.domain.domain_info = NULL;
		}
	}
	else if (fc_type->typtype == TYPTYPE_COMPOSITE || fc_typid == RECORDOID)
	{
		fc_column->typcat = TYPECAT_COMPOSITE;
		fc_column->io.composite.record_io = NULL;
		fc_column->io.composite.tupdesc = NULL;
		fc_column->io.composite.base_typid = fc_typid;
		fc_column->io.composite.base_typmod = fc_typmod;
		fc_column->io.composite.domain_info = NULL;
	}
	else if (IsTrueArrayType(fc_type))
	{
		fc_column->typcat = TYPECAT_ARRAY;
		fc_column->io.array.element_info = MemoryContextAllocZero(fc_mcxt,
															   sizeof(ColumnIOData));
		fc_column->io.array.element_type = fc_type->typelem;
		/* 数组元素类型修饰符存储在属性的 typmod 中 */
		fc_column->io.array.element_typmod = fc_typmod;
	}
	else
	{
		fc_column->typcat = TYPECAT_SCALAR;
		fc_need_scalar = true;
	}

	/* 调用者可以强制我们查找标量_io 信息，即使对于非标量 */
	if (fc_need_scalar)
	{
		Oid			fc_typioproc;

		getTypeInputInfo(fc_typid, &fc_typioproc, &fc_column->scalar_io.typioparam);
		fmgr_info_cxt(fc_typioproc, &fc_column->scalar_io.typiofunc, fc_mcxt);
	}

	ReleaseSysCache(fc_tup);
}

/* 从 json/jsonb 值递归填充记录字段或数组元素 */
static Datum fc_populate_record_field(ColumnIOData *fc_col,
					  Oid fc_typid,
					  int32 fc_typmod,
					  const char *fc_colname,
					  MemoryContext fc_mcxt,
					  Datum fc_defaultval,
					  JsValue *fc_jsv,
					  bool *fc_isnull)
{
	TypeCat		fc_typcat;

	check_stack_depth();

	/*
	 * 为给定类型准备列元数据缓存。 强制查找
	 * 标量_io 数据，以便下面的 json 字符串黑客可以工作。
	 */
	if (fc_col->typid != fc_typid || fc_col->typmod != fc_typmod)
		fc_prepare_column_cache(fc_col, fc_typid, fc_typmod, fc_mcxt, true);

	*fc_isnull = JsValueIsNull(fc_jsv);

	fc_typcat = fc_col->typcat;

	/* 尝试通过输入函数将 json 字符串转换为非标量类型 */
	if (JsValueIsString(fc_jsv) &&
		(fc_typcat == TYPECAT_ARRAY ||
		 fc_typcat == TYPECAT_COMPOSITE ||
		 fc_typcat == TYPECAT_COMPOSITE_DOMAIN))
		fc_typcat = TYPECAT_SCALAR;

	/* 我们必须对 NULL 执行域检查，否则立即退出 */
	if (*fc_isnull &&
		fc_typcat != TYPECAT_DOMAIN &&
		fc_typcat != TYPECAT_COMPOSITE_DOMAIN)
		return (Datum) 0;

	switch (fc_typcat)
	{
		case TYPECAT_SCALAR:
			return fc_populate_scalar(&fc_col->scalar_io, fc_typid, fc_typmod, fc_jsv);

		case TYPECAT_ARRAY:
			return fc_populate_array(&fc_col->io.array, fc_colname, fc_mcxt, fc_jsv);

		case TYPECAT_COMPOSITE:
		case TYPECAT_COMPOSITE_DOMAIN:
			return fc_populate_composite(&fc_col->io.composite, fc_typid,
									  fc_colname, fc_mcxt,
									  DatumGetPointer(fc_defaultval)
									  ? DatumGetHeapTupleHeader(fc_defaultval)
									  : NULL,
									  fc_jsv, *fc_isnull);

		case TYPECAT_DOMAIN:
			return fc_populate_domain(&fc_col->io.domain, fc_typid, fc_colname, fc_mcxt,
								   fc_jsv, *fc_isnull);

		default:
			elog(ERROR, "unrecognized type category '%c'", fc_typcat);
			return (Datum) 0;
	}
}

static RecordIOData *
fc_allocate_record_info(MemoryContext fc_mcxt, int fc_ncolumns)
{
	RecordIOData *fc_data = (RecordIOData *)
	MemoryContextAlloc(fc_mcxt,
					   offsetof(RecordIOData, columns) +
					   fc_ncolumns * sizeof(ColumnIOData));

	fc_data->record_type = InvalidOid;
	fc_data->record_typmod = 0;
	fc_data->ncolumns = fc_ncolumns;
	MemSet(fc_data->columns, 0, sizeof(ColumnIOData) * fc_ncolumns);

	return fc_data;
}

static bool fc_JsObjectGetField(JsObject *fc_obj, char *fc_field, JsValue *fc_jsv)
{
	fc_jsv->is_json = fc_obj->is_json;

	if (fc_jsv->is_json)
	{
		JsonHashEntry *fc_hashentry = hash_search(fc_obj->val.json_hash, fc_field,
											   HASH_FIND, NULL);

		fc_jsv->val.json.type = fc_hashentry ? fc_hashentry->type : JSON_TOKEN_NULL;
		fc_jsv->val.json.str = fc_jsv->val.json.type == JSON_TOKEN_NULL ? NULL :
			fc_hashentry->val;
		fc_jsv->val.json.len = fc_jsv->val.json.str ? -1 : 0; /* 以 null 结束 */

		return fc_hashentry != NULL;
	}
	else
	{
		fc_jsv->val.jsonb = !fc_obj->val.jsonb_cont ? NULL :
			getKeyJsonValueFromContainer(fc_obj->val.jsonb_cont, fc_field, strlen(fc_field),
										 NULL);

		return fc_jsv->val.jsonb != NULL;
	}
}

/* 从 json/jsonb 值填充记录元组 */
static HeapTupleHeader
fc_populate_record(TupleDesc fc_tupdesc,
				RecordIOData **fc_record_p,
				HeapTupleHeader fc_defaultval,
				MemoryContext fc_mcxt,
				JsObject *fc_obj)
{
	RecordIOData *fc_record = *fc_record_p;
	Datum	   *fc_values;
	bool	   *fc_nulls;
	HeapTuple	fc_res;
	int			fc_ncolumns = fc_tupdesc->natts;
	int			fc_i;

	/*
	 * 如果输入的 json 为空，只有在我们传入的是
	 * 非空记录时才能跳过其余部分，因为否则可能会出现域
	 * null 的问题。
	 */
	if (fc_defaultval && JsObjectIsEmpty(fc_obj))
		return fc_defaultval;

	/* （重新）分配元数据缓存 */
	if (fc_record == NULL ||
		fc_record->ncolumns != fc_ncolumns)
		*fc_record_p = fc_record = fc_allocate_record_info(fc_mcxt, fc_ncolumns);

	/* 如果记录类型已更改，则使元数据缓存无效 */
	if (fc_record->record_type != fc_tupdesc->tdtypeid ||
		fc_record->record_typmod != fc_tupdesc->tdtypmod)
	{
		MemSet(fc_record, 0, offsetof(RecordIOData, columns) +
			   fc_ncolumns * sizeof(ColumnIOData));
		fc_record->record_type = fc_tupdesc->tdtypeid;
		fc_record->record_typmod = fc_tupdesc->tdtypmod;
		fc_record->ncolumns = fc_ncolumns;
	}

	fc_values = (Datum *) palloc(fc_ncolumns * sizeof(Datum));
	fc_nulls = (bool *) palloc(fc_ncolumns * sizeof(bool));

	if (fc_defaultval)
	{
		HeapTupleData fc_tuple;

		/* 构建一个临时 HeapTuple 控制结构 */
		fc_tuple.t_len = HeapTupleHeaderGetDatumLength(fc_defaultval);
		ItemPointerSetInvalid(&(fc_tuple.t_self));
		fc_tuple.t_tableOid = InvalidOid;
		fc_tuple.t_data = fc_defaultval;

		/* 将元组分解为字段 */
		heap_deform_tuple(&fc_tuple, fc_tupdesc, fc_values, fc_nulls);
	}
	else
	{
		for (fc_i = 0; fc_i < fc_ncolumns; ++fc_i)
		{
			fc_values[fc_i] = (Datum) 0;
			fc_nulls[fc_i] = true;
		}
	}

	for (fc_i = 0; fc_i < fc_ncolumns; ++fc_i)
	{
		Form_pg_attribute fc_att = TupleDescAttr(fc_tupdesc, fc_i);
		char	   *fc_colname = NameStr(fc_att->attname);
		JsValue		fc_field = {0};
		bool		fc_found;

		/* 忽略数据类型中被丢弃的列 */
		if (fc_att->attisdropped)
		{
			fc_nulls[fc_i] = true;
			continue;
		}

		fc_found = fc_JsObjectGetField(fc_obj, fc_colname, &fc_field);

		/*
		 * 如果未找到键，我们不能直接跳过，因为我们可能需要处理一个域。
		 * 如果我们传递了一个非空记录数据，我们假设现有值是有效的
		 * （如果不是，那就不是我们的错），但如果我们传递了一个空值，
		 * 那么每个我们不填充的字段都需要通过输入函数处理，以防它是一个域类型。
		 */
		if (fc_defaultval && !fc_found)
			continue;

		fc_values[fc_i] = fc_populate_record_field(&fc_record->columns[fc_i],
										  fc_att->atttypid,
										  fc_att->atttypmod,
										  fc_colname,
										  fc_mcxt,
										  fc_nulls[fc_i] ? (Datum) 0 : fc_values[fc_i],
										  &fc_field,
										  &fc_nulls[fc_i]);
	}

	fc_res = heap_form_tuple(fc_tupdesc, fc_values, fc_nulls);

	pfree(fc_values);
	pfree(fc_nulls);

	return fc_res->t_data;
}

/*
 * 为 json{b}_populate_record{set} 设置：结果类型将与第一个
 * 参数的类型相同 --- 除非第一个参数是 “null::record”，我们无法
 * 从中提取类型信息；我们稍后处理。
 */
static void get_record_type_from_argument(FunctionCallInfo fcinfo,
							  const char *fc_funcname,
							  PopulateRecordCache *fc_cache)
{
	fc_cache->argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
	fc_prepare_column_cache(&fc_cache->c,
						 fc_cache->argtype, -1,
						 fc_cache->fn_mcxt, false);
	if (fc_cache->c.typcat != TYPECAT_COMPOSITE &&
		fc_cache->c.typcat != TYPECAT_COMPOSITE_DOMAIN)
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
		/* 翻译者：%s 是函数名称，例如 json_to_record */
				 errmsg("first argument of %s must be a row type",
						fc_funcname)));
}

/*
 * 为 json{b}_to_record{set} 设置：结果类型由调用
 * 查询指定。 如果我们发现第一个参数是类型 RECORD 的 null，
 * 我们也将使用此代码来处理 json{b}_populate_record{set}。
 *
 * 在这里，在语法上不可能将目标类型指定为
 * 复合类型的域。
 */
static void get_record_type_from_query(FunctionCallInfo fcinfo,
						   const char *fc_funcname,
						   PopulateRecordCache *fc_cache)
{
	TupleDesc	fc_tupdesc;
	MemoryContext fc_old_cxt;

	if (get_call_result_type(fcinfo, NULL, &fc_tupdesc) != TYPEFUNC_COMPOSITE)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
		/* 翻译者：%s 是函数名称，例如 json_to_record */
				 errmsg("could not determine row type for result of %s",
						fc_funcname),
				 errhint("Provide a non-null record argument, "
						 "or call the function in the FROM clause "
						 "using a column definition list.")));

	Assert(fc_tupdesc);
	fc_cache->argtype = fc_tupdesc->tdtypeid;

	/* 如果我们经过这一过程超过一次，避免内存泄漏 */
	if (fc_cache->c.io.composite.tupdesc)
		FreeTupleDesc(fc_cache->c.io.composite.tupdesc);

	/* 保存标识的 tupdesc */
	fc_old_cxt = MemoryContextSwitchTo(fc_cache->fn_mcxt);
	fc_cache->c.io.composite.tupdesc = CreateTupleDescCopy(fc_tupdesc);
	fc_cache->c.io.composite.base_typid = fc_tupdesc->tdtypeid;
	fc_cache->c.io.composite.base_typmod = fc_tupdesc->tdtypmod;
	MemoryContextSwitchTo(fc_old_cxt);
}

/*
 * json{b}_populate_record() 和 json{b}_to_record() 的通用工作程序
 * is_json 和 have_record_arg 确定具体函数
 */
static Datum fc_populate_record_worker(FunctionCallInfo fcinfo, const char *fc_funcname,
					   bool fc_is_json, bool fc_have_record_arg)
{
	int			fc_json_arg_num = fc_have_record_arg ? 1 : 0;
	JsValue		fc_jsv = {0};
	HeapTupleHeader fc_rec;
	Datum		fc_rettuple;
	JsonbValue	fc_jbv;
	MemoryContext fc_fnmcxt = fcinfo->flinfo->fn_mcxt;
	PopulateRecordCache *fc_cache = fcinfo->flinfo->fn_extra;

	/*
	 * 如果是第一次，识别输入/结果记录类型。 请注意
	 * 这一段只观察 fcinfo 上下文，这在查询过程中不能更改；因此
	 * 我们可能无法完全解析 RECORD 输入类型。
	 */
	if (!fc_cache)
	{
		fcinfo->flinfo->fn_extra = fc_cache =
			MemoryContextAllocZero(fc_fnmcxt, sizeof(*fc_cache));
		fc_cache->fn_mcxt = fc_fnmcxt;

		if (fc_have_record_arg)
			get_record_type_from_argument(fcinfo, fc_funcname, fc_cache);
		else
			get_record_type_from_query(fcinfo, fc_funcname, fc_cache);
	}

	/* 如果我们有记录参数，则收集它 */
	if (!fc_have_record_arg)
		fc_rec = NULL;				/* 它是 json{b}_to_record() */
	else if (!PG_ARGISNULL(0))
	{
		fc_rec = PG_GETARG_HEAPTUPLEHEADER(0);

		/*
		 * 当声明的参数类型为 RECORD 时，从元组自身识别实际的记录类型。
		 */
		if (fc_cache->argtype == RECORDOID)
		{
			fc_cache->c.io.composite.base_typid = HeapTupleHeaderGetTypeId(fc_rec);
			fc_cache->c.io.composite.base_typmod = HeapTupleHeaderGetTypMod(fc_rec);
		}
	}
	else
	{
		fc_rec = NULL;

		/*
		 * 当声明的参数类型为 RECORD 时，从调用查询识别实际的记录类型，或者在无法识别时失败。
		 */
		if (fc_cache->argtype == RECORDOID)
		{
			get_record_type_from_query(fcinfo, fc_funcname, fc_cache);
			/* 这不能更改 argtype，这对下次很重要 */
			Assert(fc_cache->argtype == RECORDOID);
		}
	}

	/* 如果没有 JSON 参数，则返回记录（如果有）不变 */
	if (PG_ARGISNULL(fc_json_arg_num))
	{
		if (fc_rec)
			PG_RETURN_POINTER(fc_rec);
		else
			PG_RETURN_NULL();
	}

	fc_jsv.is_json = fc_is_json;

	if (fc_is_json)
	{
		text	   *fc_json = PG_GETARG_TEXT_PP(fc_json_arg_num);

		fc_jsv.val.json.str = VARDATA_ANY(fc_json);
		fc_jsv.val.json.len = VARSIZE_ANY_EXHDR(fc_json);
		fc_jsv.val.json.type = JSON_TOKEN_INVALID; /* 没有在
												 * populate_composite() 中使用 */
	}
	else
	{
		Jsonb	   *fc_jb = PG_GETARG_JSONB_P(fc_json_arg_num);

		fc_jsv.val.jsonb = &fc_jbv;

		/* 填充指向 jb 的二进制 jsonb 值 */
		fc_jbv.type = jbvBinary;
		fc_jbv.val.binary.data = &fc_jb->root;
		fc_jbv.val.binary.len = VARSIZE(fc_jb) - VARHDRSZ;
	}

	fc_rettuple = fc_populate_composite(&fc_cache->c.io.composite, fc_cache->argtype,
								  NULL, fc_fnmcxt, fc_rec, &fc_jsv, false);

	PG_RETURN_DATUM(fc_rettuple);
}

/*
 * get_json_object_as_hash
 *
 * 将 JSON 对象分解为哈希表。
 */
static HTAB * get_json_object_as_hash(char *fc_json, int fc_len, const char *fc_funcname)
{
	HASHCTL		fc_ctl;
	HTAB	   *fc_tab;
	JHashState *fc_state;
	JsonLexContext *fc_lex = makeJsonLexContextCstringLen(fc_json, fc_len, GetDatabaseEncoding(), true);
	JsonSemAction *fc_sem;

	fc_ctl.keysize = NAMEDATALEN;
	fc_ctl.entrysize = sizeof(JsonHashEntry);
	fc_ctl.hcxt = CurrentMemoryContext;
	fc_tab = hash_create("json object hashtable",
					  100,
					  &fc_ctl,
					  HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);

	fc_state = palloc0(sizeof(JHashState));
	fc_sem = palloc0(sizeof(JsonSemAction));

	fc_state->function_name = fc_funcname;
	fc_state->hash = fc_tab;
	fc_state->lex = fc_lex;

	fc_sem->semstate = (void *) fc_state;
	fc_sem->array_start = fc_hash_array_start;
	fc_sem->scalar = fc_hash_scalar;
	fc_sem->object_field_start = fc_hash_object_field_start;
	fc_sem->object_field_end = fc_hash_object_field_end;

	pg_parse_json_or_ereport(fc_lex, fc_sem);

	return fc_tab;
}

static void fc_hash_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	JHashState *fc__state = (JHashState *) fc_state;

	if (fc__state->lex->lex_level > 1)
		return;

	/* 记住标记类型 */
	fc__state->saved_token_type = fc__state->lex->token_type;

	if (fc__state->lex->token_type == JSON_TOKEN_ARRAY_START ||
		fc__state->lex->token_type == JSON_TOKEN_OBJECT_START)
	{
		/* 记住子对象整个文本的起始位置 */
		fc__state->save_json_start = fc__state->lex->token_start;
	}
	else
	{
		/* 必须是标量 */
		fc__state->save_json_start = NULL;
	}
}

static void fc_hash_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull)
{
	JHashState *fc__state = (JHashState *) fc_state;
	JsonHashEntry *fc_hashentry;
	bool		fc_found;

	/*
	 * 忽略嵌套字段。
	 */
	if (fc__state->lex->lex_level > 1)
		return;

	/*
	 * 忽略字段名称 >= NAMEDATALEN - 它们无法匹配记录字段。
	 * （注意：如果没有这个测试，哈希代码将会在 NAMEDATALEN-1 处截断字符串，
	 * 然后可能会匹配相似截断的记录字段名称。这将是一个合理的行为，
	 * 但是这段代码之前坚持完全相等，因此我们保持这个行为。）
	 */
	if (strlen(fc_fname) >= NAMEDATALEN)
		return;

	fc_hashentry = hash_search(fc__state->hash, fc_fname, HASH_ENTER, &fc_found);

	/*
	 * found 为真表示存在重复。我们对此不做任何处理，
	 * 后面的同名字段会覆盖前面的字段。
	 */

	fc_hashentry->type = fc__state->saved_token_type;
	Assert(fc_isnull == (fc_hashentry->type == JSON_TOKEN_NULL));

	if (fc__state->save_json_start != NULL)
	{
		int			fc_len = fc__state->lex->prev_token_terminator - fc__state->save_json_start;
		char	   *fc_val = palloc((fc_len + 1) * sizeof(char));

		memcpy(fc_val, fc__state->save_json_start, fc_len);
		fc_val[fc_len] = '\0';
		fc_hashentry->val = fc_val;
	}
	else
	{
		/* 必须已经有一个标量 */
		fc_hashentry->val = fc__state->saved_scalar;
	}
}

static void fc_hash_array_start(void *fc_state)
{
	JHashState *fc__state = (JHashState *) fc_state;

	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on an array", fc__state->function_name)));
}

static void fc_hash_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	JHashState *fc__state = (JHashState *) fc_state;

	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on a scalar", fc__state->function_name)));

	if (fc__state->lex->lex_level == 1)
	{
		fc__state->saved_scalar = fc_token;
		/* saved_token_type 必须已经在 hash_object_field_start() 中设置 */
		Assert(fc__state->saved_token_type == fc_tokentype);
	}
}


/*
 * SQL 函数 json_populate_recordset
 *
 * 从参数 JSON 中设置一组记录的字段，
 * 该 JSON 必须是一个对象的数组。
 *
 * 类似于 json_populate_record，但元组构建代码
 * 被推送到语义动作处理程序中，因此它是逐个对象在数组中完成的。
 */
Datum jsonb_populate_recordset(PG_FUNCTION_ARGS)
{
	return fc_populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
									 false, true);
}

Datum jsonb_to_recordset(PG_FUNCTION_ARGS)
{
	return fc_populate_recordset_worker(fcinfo, "jsonb_to_recordset",
									 false, false);
}

Datum json_populate_recordset(PG_FUNCTION_ARGS)
{
	return fc_populate_recordset_worker(fcinfo, "json_populate_recordset",
									 true, true);
}

Datum json_to_recordset(PG_FUNCTION_ARGS)
{
	return fc_populate_recordset_worker(fcinfo, "json_to_recordset",
									 true, false);
}

static void fc_populate_recordset_record(PopulateRecordsetState *fc_state, JsObject *fc_obj)
{
	PopulateRecordCache *fc_cache = fc_state->cache;
	HeapTupleHeader fc_tuphead;
	HeapTupleData fc_tuple;

	/* 获取/更新缓存元组描述符 */
	update_cached_tupdesc(&fc_cache->c.io.composite, fc_cache->fn_mcxt);

	/* 从 JSON 替换记录字段 */
	fc_tuphead = fc_populate_record(fc_cache->c.io.composite.tupdesc,
							  &fc_cache->c.io.composite.record_io,
							  fc_state->rec,
							  fc_cache->fn_mcxt,
							  fc_obj);

	/* 如果它是复合类型的域，检查域约束 */
	if (fc_cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
		domain_check(HeapTupleHeaderGetDatum(fc_tuphead), false,
					 fc_cache->argtype,
					 &fc_cache->c.io.composite.domain_info,
					 fc_cache->fn_mcxt);

	/* 好的，保存到元组存储 */
	fc_tuple.t_len = HeapTupleHeaderGetDatumLength(fc_tuphead);
	ItemPointerSetInvalid(&(fc_tuple.t_self));
	fc_tuple.t_tableOid = InvalidOid;
	fc_tuple.t_data = fc_tuphead;

	tuplestore_puttuple(fc_state->tuple_store, &fc_tuple);
}

/*
 * json{b}_populate_recordset() 和 json{b}_to_recordset() 的公共工作者
 * is_json 和 have_record_arg 确认具体函数
 */
static Datum fc_populate_recordset_worker(FunctionCallInfo fcinfo, const char *fc_funcname,
						  bool fc_is_json, bool fc_have_record_arg)
{
	int			fc_json_arg_num = fc_have_record_arg ? 1 : 0;
	ReturnSetInfo *fc_rsi;
	MemoryContext fc_old_cxt;
	HeapTupleHeader fc_rec;
	PopulateRecordCache *fc_cache = fcinfo->flinfo->fn_extra;
	PopulateRecordsetState *fc_state;

	fc_rsi = (ReturnSetInfo *) fcinfo->resultinfo;

	if (!fc_rsi || !IsA(fc_rsi, ReturnSetInfo))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("set-valued function called in context that cannot accept a set")));

	if (!(fc_rsi->allowedModes & SFRM_Materialize))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("materialize mode required, but it is not allowed in this context")));

	fc_rsi->returnMode = SFRM_Materialize;

	/*
	 * 如果是第一次，识别输入/结果记录类型。 请注意
	 * 这一段只观察 fcinfo 上下文，这在查询过程中不能更改；因此
	 * 我们可能无法完全解析 RECORD 输入类型。
	 */
	if (!fc_cache)
	{
		fcinfo->flinfo->fn_extra = fc_cache =
			MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*fc_cache));
		fc_cache->fn_mcxt = fcinfo->flinfo->fn_mcxt;

		if (fc_have_record_arg)
			get_record_type_from_argument(fcinfo, fc_funcname, fc_cache);
		else
			get_record_type_from_query(fcinfo, fc_funcname, fc_cache);
	}

	/* 如果我们有记录参数，则收集它 */
	if (!fc_have_record_arg)
		fc_rec = NULL;				/* 它是 json{b}_to_recordset() */
	else if (!PG_ARGISNULL(0))
	{
		fc_rec = PG_GETARG_HEAPTUPLEHEADER(0);

		/*
		 * 当声明的参数类型为 RECORD 时，从元组自身识别实际的记录类型。
		 */
		if (fc_cache->argtype == RECORDOID)
		{
			fc_cache->c.io.composite.base_typid = HeapTupleHeaderGetTypeId(fc_rec);
			fc_cache->c.io.composite.base_typmod = HeapTupleHeaderGetTypMod(fc_rec);
		}
	}
	else
	{
		fc_rec = NULL;

		/*
		 * 当声明的参数类型为 RECORD 时，从调用查询识别实际的记录类型，或者在无法识别时失败。
		 */
		if (fc_cache->argtype == RECORDOID)
		{
			get_record_type_from_query(fcinfo, fc_funcname, fc_cache);
			/* 这不能更改 argtype，这对下次很重要 */
			Assert(fc_cache->argtype == RECORDOID);
		}
	}

	/* 如果 JSON 为 null，返回一个空集合 */
	if (PG_ARGISNULL(fc_json_arg_num))
		PG_RETURN_NULL();

	/*
	 * 强制更新缓存的 tupdesc，以确保我们拥有正确的 tupdesc，
	 * 即使 JSON 不包含任何行也能返回。
	 */
	update_cached_tupdesc(&fc_cache->c.io.composite, fc_cache->fn_mcxt);

	fc_state = palloc0(sizeof(PopulateRecordsetState));

	/* 在一个足够长活的内存上下文中创建元组存储 */
	fc_old_cxt = MemoryContextSwitchTo(fc_rsi->econtext->ecxt_per_query_memory);
	fc_state->tuple_store = tuplestore_begin_heap(fc_rsi->allowedModes &
											   SFRM_Materialize_Random,
											   false, work_mem);
	MemoryContextSwitchTo(fc_old_cxt);

	fc_state->function_name = fc_funcname;
	fc_state->cache = fc_cache;
	fc_state->rec = fc_rec;

	if (fc_is_json)
	{
		text	   *fc_json = PG_GETARG_TEXT_PP(fc_json_arg_num);
		JsonLexContext *fc_lex;
		JsonSemAction *fc_sem;

		fc_sem = palloc0(sizeof(JsonSemAction));

		fc_lex = makeJsonLexContext(fc_json, true);

		fc_sem->semstate = (void *) fc_state;
		fc_sem->array_start = fc_populate_recordset_array_start;
		fc_sem->array_element_start = fc_populate_recordset_array_element_start;
		fc_sem->scalar = fc_populate_recordset_scalar;
		fc_sem->object_field_start = fc_populate_recordset_object_field_start;
		fc_sem->object_field_end = fc_populate_recordset_object_field_end;
		fc_sem->object_start = fc_populate_recordset_object_start;
		fc_sem->object_end = fc_populate_recordset_object_end;

		fc_state->lex = fc_lex;

		pg_parse_json_or_ereport(fc_lex, fc_sem);
	}
	else
	{
		Jsonb	   *fc_jb = PG_GETARG_JSONB_P(fc_json_arg_num);
		JsonbIterator *fc_it;
		JsonbValue	fc_v;
		bool		fc_skipNested = false;
		JsonbIteratorToken fc_r;

		if (JB_ROOT_IS_SCALAR(fc_jb) || !JB_ROOT_IS_ARRAY(fc_jb))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("cannot call %s on a non-array",
							fc_funcname)));

		fc_it = JsonbIteratorInit(&fc_jb->root);

		while ((fc_r = JsonbIteratorNext(&fc_it, &fc_v, fc_skipNested)) != WJB_DONE)
		{
			fc_skipNested = true;

			if (fc_r == WJB_ELEM)
			{
				JsObject	fc_obj;

				if (fc_v.type != jbvBinary ||
					!JsonContainerIsObject(fc_v.val.binary.data))
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
							 errmsg("argument of %s must be an array of objects",
									fc_funcname)));

				fc_obj.is_json = false;
				fc_obj.val.jsonb_cont = fc_v.val.binary.data;

				fc_populate_recordset_record(fc_state, &fc_obj);
			}
		}
	}

	/*
	 * 注意：我们必须复制缓存的 tupdesc，因为执行器将释放
	 * 返回的 setDesc，但我们希望保留缓存，以防
	 * 我们在同一个查询中再被调用。
	 */
	fc_rsi->setResult = fc_state->tuple_store;
	fc_rsi->setDesc = CreateTupleDescCopy(fc_cache->c.io.composite.tupdesc);

	PG_RETURN_NULL();
}

static void fc_populate_recordset_object_start(void *fc_state)
{
	PopulateRecordsetState *fc__state = (PopulateRecordsetState *) fc_state;
	int			fc_lex_level = fc__state->lex->lex_level;
	HASHCTL		fc_ctl;

	/* 拒绝顶级的对象：我们必须在第 0 级拥有数组 */
	if (fc_lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on an object",
						fc__state->function_name)));

	/* 嵌套对象不需要特殊处理 */
	if (fc_lex_level > 1)
		return;

	/* 第 1 级的对象：为该对象设置新的哈希表 */
	fc_ctl.keysize = NAMEDATALEN;
	fc_ctl.entrysize = sizeof(JsonHashEntry);
	fc_ctl.hcxt = CurrentMemoryContext;
	fc__state->json_hash = hash_create("json object hashtable",
									100,
									&fc_ctl,
									HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
}

static void fc_populate_recordset_object_end(void *fc_state)
{
	PopulateRecordsetState *fc__state = (PopulateRecordsetState *) fc_state;
	JsObject	fc_obj;

	/* 嵌套对象不需要特殊处理 */
	if (fc__state->lex->lex_level > 1)
		return;

	fc_obj.is_json = true;
	fc_obj.val.json_hash = fc__state->json_hash;

	/* 否则，基于此第 1 级对象构造并返回一个元组 */
	fc_populate_recordset_record(fc__state, &fc_obj);

	/* 完成对象的哈希 */
	hash_destroy(fc__state->json_hash);
	fc__state->json_hash = NULL;
}

static void fc_populate_recordset_array_element_start(void *fc_state, bool fc_isnull)
{
	PopulateRecordsetState *fc__state = (PopulateRecordsetState *) fc_state;

	if (fc__state->lex->lex_level == 1 &&
		fc__state->lex->token_type != JSON_TOKEN_OBJECT_START)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("argument of %s must be an array of objects",
						fc__state->function_name)));
}

static void fc_populate_recordset_array_start(void *fc_state)
{
	/* 无需操作 */
}

static void fc_populate_recordset_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	PopulateRecordsetState *fc__state = (PopulateRecordsetState *) fc_state;

	if (fc__state->lex->lex_level == 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot call %s on a scalar",
						fc__state->function_name)));

	if (fc__state->lex->lex_level == 2)
		fc__state->saved_scalar = fc_token;
}

static void fc_populate_recordset_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	PopulateRecordsetState *fc__state = (PopulateRecordsetState *) fc_state;

	if (fc__state->lex->lex_level > 2)
		return;

	fc__state->saved_token_type = fc__state->lex->token_type;

	if (fc__state->lex->token_type == JSON_TOKEN_ARRAY_START ||
		fc__state->lex->token_type == JSON_TOKEN_OBJECT_START)
	{
		fc__state->save_json_start = fc__state->lex->token_start;
	}
	else
	{
		fc__state->save_json_start = NULL;
	}
}

static void fc_populate_recordset_object_field_end(void *fc_state, char *fc_fname, bool fc_isnull)
{
	PopulateRecordsetState *fc__state = (PopulateRecordsetState *) fc_state;
	JsonHashEntry *fc_hashentry;
	bool		fc_found;

	/*
	 * 忽略嵌套字段。
	 */
	if (fc__state->lex->lex_level > 2)
		return;

	/*
	 * 忽略字段名称 >= NAMEDATALEN - 它们无法匹配记录字段。
	 * （注意：如果没有这个测试，哈希代码将会在 NAMEDATALEN-1 处截断字符串，
	 * 然后可能会匹配相似截断的记录字段名称。这将是一个合理的行为，
	 * 但是这段代码之前坚持完全相等，因此我们保持这个行为。）
	 */
	if (strlen(fc_fname) >= NAMEDATALEN)
		return;

	fc_hashentry = hash_search(fc__state->json_hash, fc_fname, HASH_ENTER, &fc_found);

	/*
	 * found 为真表示存在重复。我们对此不做任何处理，
	 * 后面的同名字段会覆盖前面的字段。
	 */

	fc_hashentry->type = fc__state->saved_token_type;
	Assert(fc_isnull == (fc_hashentry->type == JSON_TOKEN_NULL));

	if (fc__state->save_json_start != NULL)
	{
		int			fc_len = fc__state->lex->prev_token_terminator - fc__state->save_json_start;
		char	   *fc_val = palloc((fc_len + 1) * sizeof(char));

		memcpy(fc_val, fc__state->save_json_start, fc_len);
		fc_val[fc_len] = '\0';
		fc_hashentry->val = fc_val;
	}
	else
	{
		/* 必须已经有一个标量 */
		fc_hashentry->val = fc__state->saved_scalar;
	}
}

/*
 * json_strip_nulls 的语义操作。
 *
 * 除非遇到一个 null 对象字段，否则简单地将输入重复到输出。 
 * 该状态在字段开始时设置，并在调用标量操作（必须是下一个）时重置。
 */

static void fc_sn_object_start(void *fc_state)
{
	StripnullState *fc__state = (StripnullState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, '{');
}

static void fc_sn_object_end(void *fc_state)
{
	StripnullState *fc__state = (StripnullState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, '}');
}

static void fc_sn_array_start(void *fc_state)
{
	StripnullState *fc__state = (StripnullState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, '[');
}

static void fc_sn_array_end(void *fc_state)
{
	StripnullState *fc__state = (StripnullState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, ']');
}

static void fc_sn_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	StripnullState *fc__state = (StripnullState *) fc_state;

	if (fc_isnull)
	{
		/*
		 * 下一个必须是标量，否则 isnull 不能为真，因此
		 * 这个状态不会被带入嵌套的对象或数组中没有危险。 
		 * 标志将在标量操作中重置。
		 */
		fc__state->skip_next_null = true;
		return;
	}

	if (fc__state->strval->data[fc__state->strval->len - 1] != '{')
		appendStringInfoCharMacro(fc__state->strval, ',');

	/*
	 * 不幸的是，我们不再拥有带引号和转义的字符串，因此
	 * 我们必须重新进行转义。
	 */
	escape_json(fc__state->strval, fc_fname);

	appendStringInfoCharMacro(fc__state->strval, ':');
}

static void fc_sn_array_element_start(void *fc_state, bool fc_isnull)
{
	StripnullState *fc__state = (StripnullState *) fc_state;

	if (fc__state->strval->data[fc__state->strval->len - 1] != '[')
		appendStringInfoCharMacro(fc__state->strval, ',');
}

static void fc_sn_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	StripnullState *fc__state = (StripnullState *) fc_state;

	if (fc__state->skip_next_null)
	{
		Assert(fc_tokentype == JSON_TOKEN_NULL);
		fc__state->skip_next_null = false;
		return;
	}

	if (fc_tokentype == JSON_TOKEN_STRING)
		escape_json(fc__state->strval, fc_token);
	else
		appendStringInfoString(fc__state->strval, fc_token);
}

/*
 * SQL 函数 json_strip_nulls(json) -> json
 */
Datum json_strip_nulls(PG_FUNCTION_ARGS)
{
	text	   *fc_json = PG_GETARG_TEXT_PP(0);
	StripnullState *fc_state;
	JsonLexContext *fc_lex;
	JsonSemAction *fc_sem;

	fc_lex = makeJsonLexContext(fc_json, true);
	fc_state = palloc0(sizeof(StripnullState));
	fc_sem = palloc0(sizeof(JsonSemAction));

	fc_state->strval = makeStringInfo();
	fc_state->skip_next_null = false;
	fc_state->lex = fc_lex;

	fc_sem->semstate = (void *) fc_state;
	fc_sem->object_start = fc_sn_object_start;
	fc_sem->object_end = fc_sn_object_end;
	fc_sem->array_start = fc_sn_array_start;
	fc_sem->array_end = fc_sn_array_end;
	fc_sem->scalar = fc_sn_scalar;
	fc_sem->array_element_start = fc_sn_array_element_start;
	fc_sem->object_field_start = fc_sn_object_field_start;

	pg_parse_json_or_ereport(fc_lex, fc_sem);

	PG_RETURN_TEXT_P(cstring_to_text_with_len(fc_state->strval->data,
											  fc_state->strval->len));
}

/*
 * SQL 函数 jsonb_strip_nulls(jsonb) -> jsonb
 */
Datum jsonb_strip_nulls(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	JsonbIterator *fc_it;
	JsonbParseState *fc_parseState = NULL;
	JsonbValue *fc_res = NULL;
	JsonbValue	fc_v,
				fc_k;
	JsonbIteratorToken fc_type;
	bool		fc_last_was_key = false;

	if (JB_ROOT_IS_SCALAR(fc_jb))
		PG_RETURN_POINTER(fc_jb);

	fc_it = JsonbIteratorInit(&fc_jb->root);

	while ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) != WJB_DONE)
	{
		Assert(!(fc_type == WJB_KEY && fc_last_was_key));

		if (fc_type == WJB_KEY)
		{
			/* 暂存键，直到我们知道它是否有 null 值 */
			fc_k = fc_v;
			fc_last_was_key = true;
			continue;
		}

		if (fc_last_was_key)
		{
			/* 如果最后一个元素是键，这个不能是 */
			fc_last_was_key = false;

			/* 如果值为 null，则跳过该字段 */
			if (fc_type == WJB_VALUE && fc_v.type == jbvNull)
				continue;

			/* 否则，延迟推送键 */
			(void) pushJsonbValue(&fc_parseState, WJB_KEY, &fc_k);
		}

		if (fc_type == WJB_VALUE || fc_type == WJB_ELEM)
			fc_res = pushJsonbValue(&fc_parseState, fc_type, &fc_v);
		else
			fc_res = pushJsonbValue(&fc_parseState, fc_type, NULL);
	}

	Assert(fc_res != NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_res));
}

/*
 * SQL 函数 jsonb_pretty (jsonb)
 *
 * jsonb 的美化文本
 */
Datum jsonb_pretty(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	StringInfo	fc_str = makeStringInfo();

	JsonbToCStringIndent(fc_str, &fc_jb->root, VARSIZE(fc_jb));

	PG_RETURN_TEXT_P(cstring_to_text_with_len(fc_str->data, fc_str->len));
}

/*
 * SQL 函数 jsonb_concat (jsonb, jsonb)
 *
 * || 运算符的函数
 */
Datum jsonb_concat(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb1 = PG_GETARG_JSONB_P(0);
	Jsonb	   *fc_jb2 = PG_GETARG_JSONB_P(1);
	JsonbParseState *fc_state = NULL;
	JsonbValue *fc_res;
	JsonbIterator *fc_it1,
			   *fc_it2;

	/*
	 * 如果其中一个 jsonb 为空，只需返回另一个如果它不是标量
	 * 且两个都是相同类型。如果它是标量或它们是
	 * 不同类型，我们需要执行连接，即使其中一个是
	 * 空的。
	 */
	if (JB_ROOT_IS_OBJECT(fc_jb1) == JB_ROOT_IS_OBJECT(fc_jb2))
	{
		if (JB_ROOT_COUNT(fc_jb1) == 0 && !JB_ROOT_IS_SCALAR(fc_jb2))
			PG_RETURN_JSONB_P(fc_jb2);
		else if (JB_ROOT_COUNT(fc_jb2) == 0 && !JB_ROOT_IS_SCALAR(fc_jb1))
			PG_RETURN_JSONB_P(fc_jb1);
	}

	fc_it1 = JsonbIteratorInit(&fc_jb1->root);
	fc_it2 = JsonbIteratorInit(&fc_jb2->root);

	fc_res = fc_IteratorConcat(&fc_it1, &fc_it2, &fc_state);

	Assert(fc_res != NULL);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}


/*
 * SQL 函数 jsonb_delete (jsonb, text)
 *
 * 返回一个 jsonb 的副本，删除指定的项。
 */
Datum jsonb_delete(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	text	   *fc_key = PG_GETARG_TEXT_PP(1);
	char	   *fc_keyptr = VARDATA_ANY(fc_key);
	int			fc_keylen = VARSIZE_ANY_EXHDR(fc_key);
	JsonbParseState *fc_state = NULL;
	JsonbIterator *fc_it;
	JsonbValue	fc_v,
			   *fc_res = NULL;
	bool		fc_skipNested = false;
	JsonbIteratorToken fc_r;

	if (JB_ROOT_IS_SCALAR(fc_in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot delete from scalar")));

	if (JB_ROOT_COUNT(fc_in) == 0)
		PG_RETURN_JSONB_P(fc_in);

	fc_it = JsonbIteratorInit(&fc_in->root);

	while ((fc_r = JsonbIteratorNext(&fc_it, &fc_v, fc_skipNested)) != WJB_DONE)
	{
		fc_skipNested = true;

		if ((fc_r == WJB_ELEM || fc_r == WJB_KEY) &&
			(fc_v.type == jbvString && fc_keylen == fc_v.val.string.len &&
			 memcmp(fc_keyptr, fc_v.val.string.val, fc_keylen) == 0))
		{
			/* 也跳过相应的值 */
			if (fc_r == WJB_KEY)
				(void) JsonbIteratorNext(&fc_it, &fc_v, true);

			continue;
		}

		fc_res = pushJsonbValue(&fc_state, fc_r, fc_r < WJB_BEGIN_ARRAY ? &fc_v : NULL);
	}

	Assert(fc_res != NULL);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}

/*
 * SQL 函数 jsonb_delete (jsonb, 可变文本数组[])
 *
 * 返回一个 jsonb 的副本，删除指定的项。
 */
Datum jsonb_delete_array(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	ArrayType  *fc_keys = PG_GETARG_ARRAYTYPE_P(1);
	Datum	   *fc_keys_elems;
	bool	   *fc_keys_nulls;
	int			fc_keys_len;
	JsonbParseState *fc_state = NULL;
	JsonbIterator *fc_it;
	JsonbValue	fc_v,
			   *fc_res = NULL;
	bool		fc_skipNested = false;
	JsonbIteratorToken fc_r;

	if (ARR_NDIM(fc_keys) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("wrong number of array subscripts")));

	if (JB_ROOT_IS_SCALAR(fc_in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot delete from scalar")));

	if (JB_ROOT_COUNT(fc_in) == 0)
		PG_RETURN_JSONB_P(fc_in);

	deconstruct_array(fc_keys, TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_keys_elems, &fc_keys_nulls, &fc_keys_len);

	if (fc_keys_len == 0)
		PG_RETURN_JSONB_P(fc_in);

	fc_it = JsonbIteratorInit(&fc_in->root);

	while ((fc_r = JsonbIteratorNext(&fc_it, &fc_v, fc_skipNested)) != WJB_DONE)
	{
		fc_skipNested = true;

		if ((fc_r == WJB_ELEM || fc_r == WJB_KEY) && fc_v.type == jbvString)
		{
			int			fc_i;
			bool		fc_found = false;

			for (fc_i = 0; fc_i < fc_keys_len; fc_i++)
			{
				char	   *fc_keyptr;
				int			fc_keylen;

				if (fc_keys_nulls[fc_i])
					continue;

				/* 我们依赖于数组元素未被压缩 */
				fc_keyptr = VARDATA_ANY(fc_keys_elems[fc_i]);
				fc_keylen = VARSIZE_ANY_EXHDR(fc_keys_elems[fc_i]);
				if (fc_keylen == fc_v.val.string.len &&
					memcmp(fc_keyptr, fc_v.val.string.val, fc_keylen) == 0)
				{
					fc_found = true;
					break;
				}
			}
			if (fc_found)
			{
				/* 也跳过相应的值 */
				if (fc_r == WJB_KEY)
					(void) JsonbIteratorNext(&fc_it, &fc_v, true);

				continue;
			}
		}

		fc_res = pushJsonbValue(&fc_state, fc_r, fc_r < WJB_BEGIN_ARRAY ? &fc_v : NULL);
	}

	Assert(fc_res != NULL);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}

/*
 * SQL 函数 jsonb_delete (jsonb, int)
 *
 * 返回一个 jsonb 的副本，删除指定的项。
 * 负整数意味着从项目末尾向回计数。
 */
Datum jsonb_delete_idx(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	int			fc_idx = PG_GETARG_INT32(1);
	JsonbParseState *fc_state = NULL;
	JsonbIterator *fc_it;
	uint32		fc_i = 0,
				fc_n;
	JsonbValue	fc_v,
			   *fc_res = NULL;
	JsonbIteratorToken fc_r;

	if (JB_ROOT_IS_SCALAR(fc_in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot delete from scalar")));

	if (JB_ROOT_IS_OBJECT(fc_in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot delete from object using integer index")));

	if (JB_ROOT_COUNT(fc_in) == 0)
		PG_RETURN_JSONB_P(fc_in);

	fc_it = JsonbIteratorInit(&fc_in->root);

	fc_r = JsonbIteratorNext(&fc_it, &fc_v, false);
	Assert(fc_r == WJB_BEGIN_ARRAY);
	fc_n = fc_v.val.array.nElems;

	if (fc_idx < 0)
	{
		if (-fc_idx > fc_n)
			fc_idx = fc_n;
		else
			fc_idx = fc_n + fc_idx;
	}

	if (fc_idx >= fc_n)
		PG_RETURN_JSONB_P(fc_in);

	pushJsonbValue(&fc_state, fc_r, NULL);

	while ((fc_r = JsonbIteratorNext(&fc_it, &fc_v, true)) != WJB_DONE)
	{
		if (fc_r == WJB_ELEM)
		{
			if (fc_i++ == fc_idx)
				continue;
		}

		fc_res = pushJsonbValue(&fc_state, fc_r, fc_r < WJB_BEGIN_ARRAY ? &fc_v : NULL);
	}

	Assert(fc_res != NULL);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}

/*
 * SQL 函数 jsonb_set(jsonb, text[], jsonb, boolean)
 */
Datum jsonb_set(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	ArrayType  *fc_path = PG_GETARG_ARRAYTYPE_P(1);
	Jsonb	   *fc_newjsonb = PG_GETARG_JSONB_P(2);
	JsonbValue	fc_newval;
	bool		fc_create = PG_GETARG_BOOL(3);
	JsonbValue *fc_res = NULL;
	Datum	   *fc_path_elems;
	bool	   *fc_path_nulls;
	int			fc_path_len;
	JsonbIterator *fc_it;
	JsonbParseState *fc_st = NULL;

	JsonbToJsonbValue(fc_newjsonb, &fc_newval);

	if (ARR_NDIM(fc_path) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("wrong number of array subscripts")));

	if (JB_ROOT_IS_SCALAR(fc_in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot set path in scalar")));

	if (JB_ROOT_COUNT(fc_in) == 0 && !fc_create)
		PG_RETURN_JSONB_P(fc_in);

	deconstruct_array(fc_path, TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_path_elems, &fc_path_nulls, &fc_path_len);

	if (fc_path_len == 0)
		PG_RETURN_JSONB_P(fc_in);

	fc_it = JsonbIteratorInit(&fc_in->root);

	fc_res = fc_setPath(&fc_it, fc_path_elems, fc_path_nulls, fc_path_len, &fc_st,
				  0, &fc_newval, fc_create ? JB_PATH_CREATE : JB_PATH_REPLACE);

	Assert(fc_res != NULL);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}


/*
 * SQL 函数 jsonb_set_lax(jsonb, text[], jsonb, boolean, text)
 */
Datum jsonb_set_lax(PG_FUNCTION_ARGS)
{
	/* Jsonb	   *in = PG_GETARG_JSONB_P(0); */
	/* ArrayType  *path = PG_GETARG_ARRAYTYPE_P(1); */
	/* Jsonb	  *newval = PG_GETARG_JSONB_P(2); */
	/* bool		create = PG_GETARG_BOOL(3); */
	text	   *fc_handle_null;
	char	   *fc_handle_val;

	if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(3))
		PG_RETURN_NULL();

	/* 如果传入了显式 NULL，可能会发生此情况 */
	if (PG_ARGISNULL(4))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));

	/* 如果新值不是 SQL NULL，则直接调用 jsonb_set */
	if (!PG_ARGISNULL(2))
		return jsonb_set(fcinfo);

	fc_handle_null = PG_GETARG_TEXT_P(4);
	fc_handle_val = text_to_cstring(fc_handle_null);

	if (strcmp(fc_handle_val, "raise_exception") == 0)
	{
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("JSON value must not be null"),
				 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
				 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
		return (Datum) 0;		/* 消除愚蠢编译器的警告 */
	}
	else if (strcmp(fc_handle_val, "use_json_null") == 0)
	{
		Datum		fc_newval;

		fc_newval = DirectFunctionCall1(jsonb_in, CStringGetDatum("null"));

		fcinfo->args[2].value = fc_newval;
		fcinfo->args[2].isnull = false;
		return jsonb_set(fcinfo);
	}
	else if (strcmp(fc_handle_val, "delete_key") == 0)
	{
		return jsonb_delete_path(fcinfo);
	}
	else if (strcmp(fc_handle_val, "return_target") == 0)
	{
		Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);

		PG_RETURN_JSONB_P(fc_in);
	}
	else
	{
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
		return (Datum) 0;		/* 消除愚蠢编译器的警告 */
	}
}

/*
 * SQL 函数 jsonb_delete_path(jsonb, text[])
 */
Datum jsonb_delete_path(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	ArrayType  *fc_path = PG_GETARG_ARRAYTYPE_P(1);
	JsonbValue *fc_res = NULL;
	Datum	   *fc_path_elems;
	bool	   *fc_path_nulls;
	int			fc_path_len;
	JsonbIterator *fc_it;
	JsonbParseState *fc_st = NULL;

	if (ARR_NDIM(fc_path) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("wrong number of array subscripts")));

	if (JB_ROOT_IS_SCALAR(fc_in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot delete path in scalar")));

	if (JB_ROOT_COUNT(fc_in) == 0)
		PG_RETURN_JSONB_P(fc_in);

	deconstruct_array(fc_path, TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_path_elems, &fc_path_nulls, &fc_path_len);

	if (fc_path_len == 0)
		PG_RETURN_JSONB_P(fc_in);

	fc_it = JsonbIteratorInit(&fc_in->root);

	fc_res = fc_setPath(&fc_it, fc_path_elems, fc_path_nulls, fc_path_len, &fc_st,
				  0, NULL, JB_PATH_DELETE);

	Assert(fc_res != NULL);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}

/*
 * SQL 函数 jsonb_insert(jsonb, text[], jsonb, boolean)
 */
Datum jsonb_insert(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	ArrayType  *fc_path = PG_GETARG_ARRAYTYPE_P(1);
	Jsonb	   *fc_newjsonb = PG_GETARG_JSONB_P(2);
	JsonbValue	fc_newval;
	bool		fc_after = PG_GETARG_BOOL(3);
	JsonbValue *fc_res = NULL;
	Datum	   *fc_path_elems;
	bool	   *fc_path_nulls;
	int			fc_path_len;
	JsonbIterator *fc_it;
	JsonbParseState *fc_st = NULL;

	JsonbToJsonbValue(fc_newjsonb, &fc_newval);

	if (ARR_NDIM(fc_path) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("wrong number of array subscripts")));

	if (JB_ROOT_IS_SCALAR(fc_in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot set path in scalar")));

	deconstruct_array(fc_path, TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_path_elems, &fc_path_nulls, &fc_path_len);

	if (fc_path_len == 0)
		PG_RETURN_JSONB_P(fc_in);

	fc_it = JsonbIteratorInit(&fc_in->root);

	fc_res = fc_setPath(&fc_it, fc_path_elems, fc_path_nulls, fc_path_len, &fc_st, 0, &fc_newval,
				  fc_after ? JB_PATH_INSERT_AFTER : JB_PATH_INSERT_BEFORE);

	Assert(fc_res != NULL);

	PG_RETURN_JSONB_P(JsonbValueToJsonb(fc_res));
}

/*
 * 迭代所有 jsonb 对象并将它们合并为一个。
 * 此函数的逻辑来自相同的 hstore 函数，
 * 除非 it1 和 it2 表示 jbvObject 的情况。
 * 在这种情况下，我们只需将 it2 的内容附加到 it1
 * 而不进行任何验证。
 */
static JsonbValue * fc_IteratorConcat(JsonbIterator **fc_it1, JsonbIterator **fc_it2,
			   JsonbParseState **fc_state)
{
	JsonbValue	fc_v1,
				fc_v2,
			   *fc_res = NULL;
	JsonbIteratorToken fc_r1,
				fc_r2,
				fc_rk1,
				fc_rk2;

	fc_rk1 = JsonbIteratorNext(fc_it1, &fc_v1, false);
	fc_rk2 = JsonbIteratorNext(fc_it2, &fc_v2, false);

	/*
	 * JsonbIteratorNext 将原始标量报告为单元素
	 * 数组；因此我们只需考虑“对象”和“数组”情况。
	 */
	if (fc_rk1 == WJB_BEGIN_OBJECT && fc_rk2 == WJB_BEGIN_OBJECT)
	{
		/*
		 * 两个输入都是对象。
		 *
		 * 将 v1 中的所有标记附加到 res，除了最后的 WJB_END_OBJECT
		 * （因为 res 还未完成）。
		 */
		pushJsonbValue(fc_state, fc_rk1, NULL);
		while ((fc_r1 = JsonbIteratorNext(fc_it1, &fc_v1, true)) != WJB_END_OBJECT)
			pushJsonbValue(fc_state, fc_r1, &fc_v1);

		/*
		 * 将所有来自v2的标记追加到res，包括最后的WJB_END_OBJECT
		 * （连接将完成）。任何重复的键将自动覆盖第一个对象的值。
		 */
		while ((fc_r2 = JsonbIteratorNext(fc_it2, &fc_v2, true)) != WJB_DONE)
			fc_res = pushJsonbValue(fc_state, fc_r2, fc_r2 != WJB_END_OBJECT ? &fc_v2 : NULL);
	}
	else if (fc_rk1 == WJB_BEGIN_ARRAY && fc_rk2 == WJB_BEGIN_ARRAY)
	{
		/*
		 * 两个输入都是数组。
		 */
		pushJsonbValue(fc_state, fc_rk1, NULL);

		while ((fc_r1 = JsonbIteratorNext(fc_it1, &fc_v1, true)) != WJB_END_ARRAY)
		{
			Assert(fc_r1 == WJB_ELEM);
			pushJsonbValue(fc_state, fc_r1, &fc_v1);
		}

		while ((fc_r2 = JsonbIteratorNext(fc_it2, &fc_v2, true)) != WJB_END_ARRAY)
		{
			Assert(fc_r2 == WJB_ELEM);
			pushJsonbValue(fc_state, WJB_ELEM, &fc_v2);
		}

		fc_res = pushJsonbValue(fc_state, WJB_END_ARRAY, NULL /* 信号以进行排序 */ );
	}
	else if (fc_rk1 == WJB_BEGIN_OBJECT)
	{
		/*
		 * 我们有对象 || 数组。
		 */
		Assert(fc_rk2 == WJB_BEGIN_ARRAY);

		pushJsonbValue(fc_state, WJB_BEGIN_ARRAY, NULL);

		pushJsonbValue(fc_state, WJB_BEGIN_OBJECT, NULL);
		while ((fc_r1 = JsonbIteratorNext(fc_it1, &fc_v1, true)) != WJB_DONE)
			pushJsonbValue(fc_state, fc_r1, fc_r1 != WJB_END_OBJECT ? &fc_v1 : NULL);

		while ((fc_r2 = JsonbIteratorNext(fc_it2, &fc_v2, true)) != WJB_DONE)
			fc_res = pushJsonbValue(fc_state, fc_r2, fc_r2 != WJB_END_ARRAY ? &fc_v2 : NULL);
	}
	else
	{
		/*
		 * 我们有数组 || 对象。
		 */
		Assert(fc_rk1 == WJB_BEGIN_ARRAY);
		Assert(fc_rk2 == WJB_BEGIN_OBJECT);

		pushJsonbValue(fc_state, WJB_BEGIN_ARRAY, NULL);

		while ((fc_r1 = JsonbIteratorNext(fc_it1, &fc_v1, true)) != WJB_END_ARRAY)
			pushJsonbValue(fc_state, fc_r1, &fc_v1);

		pushJsonbValue(fc_state, WJB_BEGIN_OBJECT, NULL);
		while ((fc_r2 = JsonbIteratorNext(fc_it2, &fc_v2, true)) != WJB_DONE)
			pushJsonbValue(fc_state, fc_r2, fc_r2 != WJB_END_OBJECT ? &fc_v2 : NULL);

		fc_res = pushJsonbValue(fc_state, WJB_END_ARRAY, NULL);
	}

	return fc_res;
}

/*
 * 为jsonb_set/jsonb_insert执行大部分重工
 *
 * 如果在op_type中设置了JB_PATH_DELETE位，则该元素将被移除。
 *
 * 如果在op_type中设置了JB_PATH_CREATE_OR_INSERT中提到的任何位，
 * 如果键或数组索引不存在，我们创建新值。
 *
 * 在op_type中，JB_PATH_INSERT_BEFORE和JB_PATH_INSERT_AFTER位
 * 在插入到JsonbObject时表现得像JB_PATH_CREATE。
 *
 * 如果设置了JB_PATH_FILL_GAPS位，这将在目标为数组的情况下
 * 更改赋值逻辑。赋值索引将不受数组中元素数量的限制；
 * 如果数组中最后一个元素与新元素之间有任何空槽，它们将被填充为null。
 * 如果索引为负数，它仍然将被视为从数组末尾的索引。
 * 如果路径的一部分不存在，并且此部分不仅仅是最后一个元素，
 * 此标志将指示创建整个相应对象链并插入值。
 *
 * JB_PATH_CONSISTENT_POSITION用于数组表示调用者希望保持固定索引的值。
 * 如果数组前面插入了新值，现有元素的索引可能会被更改（向前移动），
 * 因此将防止这种行为并返回错误。
 *
 * 在最后之前的所有路径元素必须已经存在
 * 无论op_type中设置了什么位，否则将不执行任何操作。
 */
static JsonbValue * fc_setPath(JsonbIterator **fc_it, Datum *fc_path_elems,
		bool *fc_path_nulls, int fc_path_len,
		JsonbParseState **fc_st, int fc_level, JsonbValue *fc_newval, int fc_op_type)
{
	JsonbValue	fc_v;
	JsonbIteratorToken fc_r;
	JsonbValue *fc_res;

	check_stack_depth();

	if (fc_path_nulls[fc_level])
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("path element at position %d is null",
						fc_level + 1)));

	fc_r = JsonbIteratorNext(fc_it, &fc_v, false);

	switch (fc_r)
	{
		case WJB_BEGIN_ARRAY:

			/*
			 * 如果被指示，抱怨尝试在原始标量值内进行替换。
			 * 即使当前级别等于path_len，这也会发生，因为最后的路径键
			 * 也应对应一个对象或数组，而不是原始标量。
			 */
			if ((fc_op_type & JB_PATH_FILL_GAPS) && (fc_level <= fc_path_len - 1) &&
				fc_v.val.array.rawScalar)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("cannot replace existing key"),
						 errdetail("The path assumes key is a composite object, "
								   "but it is a scalar value.")));

			(void) pushJsonbValue(fc_st, fc_r, NULL);
			fc_setPathArray(fc_it, fc_path_elems, fc_path_nulls, fc_path_len, fc_st, fc_level,
						 fc_newval, fc_v.val.array.nElems, fc_op_type);
			fc_r = JsonbIteratorNext(fc_it, &fc_v, false);
			Assert(fc_r == WJB_END_ARRAY);
			fc_res = pushJsonbValue(fc_st, fc_r, NULL);
			break;
		case WJB_BEGIN_OBJECT:
			(void) pushJsonbValue(fc_st, fc_r, NULL);
			fc_setPathObject(fc_it, fc_path_elems, fc_path_nulls, fc_path_len, fc_st, fc_level,
						  fc_newval, fc_v.val.object.nPairs, fc_op_type);
			fc_r = JsonbIteratorNext(fc_it, &fc_v, true);
			Assert(fc_r == WJB_END_OBJECT);
			fc_res = pushJsonbValue(fc_st, fc_r, NULL);
			break;
		case WJB_ELEM:
		case WJB_VALUE:

			/*
			 * 如果被指示，抱怨尝试在标量值内进行替换。
			 * 即使当前级别等于path_len，这也会发生，因为最后的路径键
			 * 也应对应一个对象或数组，而不是元素或值。
			 */
			if ((fc_op_type & JB_PATH_FILL_GAPS) && (fc_level <= fc_path_len - 1))
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("cannot replace existing key"),
						 errdetail("The path assumes key is a composite object, "
								   "but it is a scalar value.")));

			fc_res = pushJsonbValue(fc_st, fc_r, &fc_v);
			break;
		default:
			elog(ERROR, "unrecognized iterator result: %d", (int) fc_r);
			fc_res = NULL;			/* 保持编译器安静 */
			break;
	}

	return fc_res;
}

/*
 * 用于setPath的对象遍历器
 */
static void fc_setPathObject(JsonbIterator **fc_it, Datum *fc_path_elems, bool *fc_path_nulls,
			  int fc_path_len, JsonbParseState **fc_st, int fc_level,
			  JsonbValue *fc_newval, uint32 fc_npairs, int fc_op_type)
{
	text	   *fc_pathelem = NULL;
	int			fc_i;
	JsonbValue	fc_k,
				fc_v;
	bool		fc_done = false;

	if (fc_level >= fc_path_len || fc_path_nulls[fc_level])
		fc_done = true;
	else
	{
		/* 路径Datum可能被烤制，在这种情况下，我们必须进行解烤 */
		fc_pathelem = DatumGetTextPP(fc_path_elems[fc_level]);
	}

	/* 空对象是创建的特殊情况 */
	if ((fc_npairs == 0) && (fc_op_type & JB_PATH_CREATE_OR_INSERT) &&
		(fc_level == fc_path_len - 1))
	{
		JsonbValue	fc_newkey;

		fc_newkey.type = jbvString;
		fc_newkey.val.string.val = VARDATA_ANY(fc_pathelem);
		fc_newkey.val.string.len = VARSIZE_ANY_EXHDR(fc_pathelem);

		(void) pushJsonbValue(fc_st, WJB_KEY, &fc_newkey);
		(void) pushJsonbValue(fc_st, WJB_VALUE, fc_newval);
	}

	for (fc_i = 0; fc_i < fc_npairs; fc_i++)
	{
		JsonbIteratorToken fc_r = JsonbIteratorNext(fc_it, &fc_k, true);

		Assert(fc_r == WJB_KEY);

		if (!fc_done &&
			fc_k.val.string.len == VARSIZE_ANY_EXHDR(fc_pathelem) &&
			memcmp(fc_k.val.string.val, VARDATA_ANY(fc_pathelem),
				   fc_k.val.string.len) == 0)
		{
			fc_done = true;

			if (fc_level == fc_path_len - 1)
			{
				/*
				 * 从jsonb_insert()调用，它禁止重新定义现有值
				 */
				if (fc_op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER))
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
							 errmsg("cannot replace existing key"),
							 errhint("Try using the function jsonb_set "
									 "to replace key value.")));

				fc_r = JsonbIteratorNext(fc_it, &fc_v, true);	/* 跳过值 */
				if (!(fc_op_type & JB_PATH_DELETE))
				{
					(void) pushJsonbValue(fc_st, WJB_KEY, &fc_k);
					(void) pushJsonbValue(fc_st, WJB_VALUE, fc_newval);
				}
			}
			else
			{
				(void) pushJsonbValue(fc_st, fc_r, &fc_k);
				fc_setPath(fc_it, fc_path_elems, fc_path_nulls, fc_path_len,
						fc_st, fc_level + 1, fc_newval, fc_op_type);
			}
		}
		else
		{
			if ((fc_op_type & JB_PATH_CREATE_OR_INSERT) && !fc_done &&
				fc_level == fc_path_len - 1 && fc_i == fc_npairs - 1)
			{
				JsonbValue	fc_newkey;

				fc_newkey.type = jbvString;
				fc_newkey.val.string.val = VARDATA_ANY(fc_pathelem);
				fc_newkey.val.string.len = VARSIZE_ANY_EXHDR(fc_pathelem);

				(void) pushJsonbValue(fc_st, WJB_KEY, &fc_newkey);
				(void) pushJsonbValue(fc_st, WJB_VALUE, fc_newval);
			}

			(void) pushJsonbValue(fc_st, fc_r, &fc_k);
			fc_r = JsonbIteratorNext(fc_it, &fc_v, false);
			(void) pushJsonbValue(fc_st, fc_r, fc_r < WJB_BEGIN_ARRAY ? &fc_v : NULL);
			if (fc_r == WJB_BEGIN_ARRAY || fc_r == WJB_BEGIN_OBJECT)
			{
				int			fc_walking_level = 1;

				while (fc_walking_level != 0)
				{
					fc_r = JsonbIteratorNext(fc_it, &fc_v, false);

					if (fc_r == WJB_BEGIN_ARRAY || fc_r == WJB_BEGIN_OBJECT)
						++fc_walking_level;
					if (fc_r == WJB_END_ARRAY || fc_r == WJB_END_OBJECT)
						--fc_walking_level;

					(void) pushJsonbValue(fc_st, fc_r, fc_r < WJB_BEGIN_ARRAY ? &fc_v : NULL);
				}
			}
		}
	}

	/*--
	 * 如果我们到了这里，那只有几种可能性：
	 * - 没有找到目标路径，一个带有一些键/值的开放对象被推入状态
	 * - 对象为空，仅推入WJB_BEGIN_OBJECT
	 *
	 * 在这两种情况下，若被指示在缺失时创建路径，
	 * 生成整个空对象链并在其中插入新值。
	 */
	if (!fc_done && (fc_op_type & JB_PATH_FILL_GAPS) && (fc_level < fc_path_len - 1))
	{
		JsonbValue	fc_newkey;

		fc_newkey.type = jbvString;
		fc_newkey.val.string.val = VARDATA_ANY(fc_pathelem);
		fc_newkey.val.string.len = VARSIZE_ANY_EXHDR(fc_pathelem);

		(void) pushJsonbValue(fc_st, WJB_KEY, &fc_newkey);
		(void) fc_push_path(fc_st, fc_level, fc_path_elems, fc_path_nulls,
						 fc_path_len, fc_newval);

		/* 结果在此函数外部用WJB_END_OBJECT关闭 */
	}
}

/*
 * 用于setPath的数组遍历器
 */
static void fc_setPathArray(JsonbIterator **fc_it, Datum *fc_path_elems, bool *fc_path_nulls,
			 int fc_path_len, JsonbParseState **fc_st, int fc_level,
			 JsonbValue *fc_newval, uint32 fc_nelems, int fc_op_type)
{
	JsonbValue	fc_v;
	int			fc_idx,
				fc_i;
	bool		fc_done = false;

	/* 选择正确的索引 */
	if (fc_level < fc_path_len && !fc_path_nulls[fc_level])
	{
		char	   *fc_c = TextDatumGetCString(fc_path_elems[fc_level]);
		char	   *fc_badp;

		errno = 0;
		fc_idx = strtoint(fc_c, &fc_badp, 10);
		if (fc_badp == fc_c || *fc_badp != '\0' || errno != 0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("path element at position %d is not an integer: \"%s\"",
							fc_level + 1, fc_c)));
	}
	else
		fc_idx = fc_nelems;

	if (fc_idx < 0)
	{
		if (-fc_idx > fc_nelems)
		{
			/*
			 * 如果要求保持元素位置一致，则不允许在数组前插入。
			 */
			if (fc_op_type & JB_PATH_CONSISTENT_POSITION)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("path element at position %d is out of range: %d",
								fc_level + 1, fc_idx)));
			else
				fc_idx = INT_MIN;
		}
		else
			fc_idx = fc_nelems + fc_idx;
	}

	/*
	 * 填充空位意味着对正索引没有施加限制，
	 * 我们可以设置任何元素。否则限制索引为nelems。
	 */
	if (!(fc_op_type & JB_PATH_FILL_GAPS))
	{
		if (fc_idx > 0 && fc_idx > fc_nelems)
			fc_idx = fc_nelems;
	}

	/*
	 * 如果我们正在创建，并且idx == INT_MIN，若数组为空也将新值插入到
	 * 数组前 - 在这种情况下我们并不关心idx的值是什么。
	 */
	if ((fc_idx == INT_MIN || fc_nelems == 0) && (fc_level == fc_path_len - 1) &&
		(fc_op_type & JB_PATH_CREATE_OR_INSERT))
	{
		Assert(fc_newval != NULL);

		if (fc_op_type & JB_PATH_FILL_GAPS && fc_nelems == 0 && fc_idx > 0)
			fc_push_null_elements(fc_st, fc_idx);

		(void) pushJsonbValue(fc_st, WJB_ELEM, fc_newval);

		fc_done = true;
	}

	/* 遍历数组元素 */
	for (fc_i = 0; fc_i < fc_nelems; fc_i++)
	{
		JsonbIteratorToken fc_r;

		if (fc_i == fc_idx && fc_level < fc_path_len)
		{
			fc_done = true;

			if (fc_level == fc_path_len - 1)
			{
				fc_r = JsonbIteratorNext(fc_it, &fc_v, true);	/* 跳过 */

				if (fc_op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE))
					(void) pushJsonbValue(fc_st, WJB_ELEM, fc_newval);

				/*
				 * 只有在JB_PATH_INSERT_BEFORE或JB_PATH_INSERT_AFTER的情况下
				 * 我们才应该保留当前值，因为否则它应该被删除或替换。
				 */
				if (fc_op_type & (JB_PATH_INSERT_AFTER | JB_PATH_INSERT_BEFORE))
					(void) pushJsonbValue(fc_st, fc_r, &fc_v);

				if (fc_op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE))
					(void) pushJsonbValue(fc_st, WJB_ELEM, fc_newval);
			}
			else
				(void) fc_setPath(fc_it, fc_path_elems, fc_path_nulls, fc_path_len,
							   fc_st, fc_level + 1, fc_newval, fc_op_type);
		}
		else
		{
			fc_r = JsonbIteratorNext(fc_it, &fc_v, false);

			(void) pushJsonbValue(fc_st, fc_r, fc_r < WJB_BEGIN_ARRAY ? &fc_v : NULL);

			if (fc_r == WJB_BEGIN_ARRAY || fc_r == WJB_BEGIN_OBJECT)
			{
				int			fc_walking_level = 1;

				while (fc_walking_level != 0)
				{
					fc_r = JsonbIteratorNext(fc_it, &fc_v, false);

					if (fc_r == WJB_BEGIN_ARRAY || fc_r == WJB_BEGIN_OBJECT)
						++fc_walking_level;
					if (fc_r == WJB_END_ARRAY || fc_r == WJB_END_OBJECT)
						--fc_walking_level;

					(void) pushJsonbValue(fc_st, fc_r, fc_r < WJB_BEGIN_ARRAY ? &fc_v : NULL);
				}
			}
		}
	}

	if ((fc_op_type & JB_PATH_CREATE_OR_INSERT) && !fc_done && fc_level == fc_path_len - 1)
	{
		/*
		 * 如果要求填补空缺，则idx可能比nelems大，
		 * 因此在这种情况下用null填充新的元素。
		 */
		if (fc_op_type & JB_PATH_FILL_GAPS && fc_idx > fc_nelems)
			fc_push_null_elements(fc_st, fc_idx - fc_nelems);

		(void) pushJsonbValue(fc_st, WJB_ELEM, fc_newval);
		fc_done = true;
	}

	/*--
	 * 如果我们到了这里，那只有几种可能性：
	 * - 没有找到目标路径，一个带有一些键/值的开放数组被推入状态
	 * - 数组为空，仅推入WJB_BEGIN_ARRAY
	 *
	 * 在这两种情况下，若被指示在缺失时创建路径，
	 * 生成整个空对象链并在其中插入新值。
	 */
	if (!fc_done && (fc_op_type & JB_PATH_FILL_GAPS) && (fc_level < fc_path_len - 1))
	{
		if (fc_idx > 0)
			fc_push_null_elements(fc_st, fc_idx - fc_nelems);

		(void) fc_push_path(fc_st, fc_level, fc_path_elems, fc_path_nulls,
						 fc_path_len, fc_newval);

		/* 结果在此函数外部用WJB_END_OBJECT关闭 */
	}
}

/*
 * 解析有关我们想要在函数iterate_json(b)_values中迭代的jsonb文档的元素信息。
 * 这些信息以jsonb格式呈现，以便将来可以轻松扩展。
 */
uint32 parse_jsonb_index_flags(Jsonb *fc_jb)
{
	JsonbIterator *fc_it;
	JsonbValue	fc_v;
	JsonbIteratorToken fc_type;
	uint32		fc_flags = 0;

	fc_it = JsonbIteratorInit(&fc_jb->root);

	fc_type = JsonbIteratorNext(&fc_it, &fc_v, false);

	/*
	 * 我们遍历数组（标量在内部被表示为数组，因此，
	 * 我们也接受它）以检查所有元素。标志名称与jsonb_typeof使用的相同。
	 */
	if (fc_type != WJB_BEGIN_ARRAY)
		ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						errmsg("wrong flag type, only arrays and scalars are allowed")));

	while ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) == WJB_ELEM)
	{
		if (fc_v.type != jbvString)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("flag array element is not a string"),
					 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));

		if (fc_v.val.string.len == 3 &&
			pg_strncasecmp(fc_v.val.string.val, "all", 3) == 0)
			fc_flags |= jtiAll;
		else if (fc_v.val.string.len == 3 &&
				 pg_strncasecmp(fc_v.val.string.val, "key", 3) == 0)
			fc_flags |= jtiKey;
		else if (fc_v.val.string.len == 6 &&
				 pg_strncasecmp(fc_v.val.string.val, "string", 6) == 0)
			fc_flags |= jtiString;
		else if (fc_v.val.string.len == 7 &&
				 pg_strncasecmp(fc_v.val.string.val, "numeric", 7) == 0)
			fc_flags |= jtiNumeric;
		else if (fc_v.val.string.len == 7 &&
				 pg_strncasecmp(fc_v.val.string.val, "boolean", 7) == 0)
			fc_flags |= jtiBool;
		else
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("wrong flag in flag array: \"%s\"",
							pnstrdup(fc_v.val.string.val, fc_v.val.string.len)),
					 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\", and \"all\".")));
	}

	
/* 现在期望数组结束 */
	if (fc_type != WJB_END_ARRAY)
		elog(ERROR, "unexpected end of flag array");

	/* 获取最终的 WJB_DONE 并释放迭代器 */
	fc_type = JsonbIteratorNext(&fc_it, &fc_v, false);
	if (fc_type != WJB_DONE)
		elog(ERROR, "unexpected end of flag array");

	return fc_flags;
}

/*
 * 根据标志迭代 jsonb 值或元素，并将它们
 * 与迭代状态一起传递给指定的 JsonIterateStringValuesAction。
 */
void iterate_jsonb_values(Jsonb *fc_jb, uint32 fc_flags, void *fc_state,
					 JsonIterateStringValuesAction fc_action)
{
	JsonbIterator *fc_it;
	JsonbValue	fc_v;
	JsonbIteratorToken fc_type;

	fc_it = JsonbIteratorInit(&fc_jb->root);

	/*
	 * 只是递归地迭代 jsonb 并对所有
	 * 对应的元素调用回调
	 */
	while ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) != WJB_DONE)
	{
		if (fc_type == WJB_KEY)
		{
			if (fc_flags & jtiKey)
				fc_action(fc_state, fc_v.val.string.val, fc_v.val.string.len);

			continue;
		}
		else if (!(fc_type == WJB_VALUE || fc_type == WJB_ELEM))
		{
			/* 不要对复合 JsonbValue 调用回调 */
			continue;
		}

		/* JsonbValue 是对象的值或数组的元素 */
		switch (fc_v.type)
		{
			case jbvString:
				if (fc_flags & jtiString)
					fc_action(fc_state, fc_v.val.string.val, fc_v.val.string.len);
				break;
			case jbvNumeric:
				if (fc_flags & jtiNumeric)
				{
					char	   *fc_val;

					fc_val = DatumGetCString(DirectFunctionCall1(numeric_out,
															  NumericGetDatum(fc_v.val.numeric)));

					fc_action(fc_state, fc_val, strlen(fc_val));
					pfree(fc_val);
				}
				break;
			case jbvBool:
				if (fc_flags & jtiBool)
				{
					if (fc_v.val.boolean)
						fc_action(fc_state, "true", 4);
					else
						fc_action(fc_state, "false", 5);
				}
				break;
			default:
				/* 不要对复合 JsonbValue 调用回调 */
				break;
		}
	}
}

/*
 * 遍历 json 值和元素，根据标志进行指定，并将它们
 * 与迭代状态一起传递给指定的 JsonIterateStringValuesAction。
 */
void iterate_json_values(text *fc_json, uint32 fc_flags, void *fc_action_state,
					JsonIterateStringValuesAction fc_action)
{
	JsonLexContext *fc_lex = makeJsonLexContext(fc_json, true);
	JsonSemAction *fc_sem = palloc0(sizeof(JsonSemAction));
	IterateJsonStringValuesState *fc_state = palloc0(sizeof(IterateJsonStringValuesState));

	fc_state->lex = fc_lex;
	fc_state->action = fc_action;
	fc_state->action_state = fc_action_state;
	fc_state->flags = fc_flags;

	fc_sem->semstate = (void *) fc_state;
	fc_sem->scalar = fc_iterate_values_scalar;
	fc_sem->object_field_start = fc_iterate_values_object_field_start;

	pg_parse_json_or_ereport(fc_lex, fc_sem);
}

/*
 * iterate_json_values 的辅助函数，用于对指定值调用
 * 指定的 JsonIterateStringValuesAction。
 */
static void fc_iterate_values_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	IterateJsonStringValuesState *fc__state = (IterateJsonStringValuesState *) fc_state;

	switch (fc_tokentype)
	{
		case JSON_TOKEN_STRING:
			if (fc__state->flags & jtiString)
				fc__state->action(fc__state->action_state, fc_token, strlen(fc_token));
			break;
		case JSON_TOKEN_NUMBER:
			if (fc__state->flags & jtiNumeric)
				fc__state->action(fc__state->action_state, fc_token, strlen(fc_token));
			break;
		case JSON_TOKEN_TRUE:
		case JSON_TOKEN_FALSE:
			if (fc__state->flags & jtiBool)
				fc__state->action(fc__state->action_state, fc_token, strlen(fc_token));
			break;
		default:
			/* 不要对任何其他令牌调用回调 */
			break;
	}
}

static void fc_iterate_values_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	IterateJsonStringValuesState *fc__state = (IterateJsonStringValuesState *) fc_state;

	if (fc__state->flags & jtiKey)
	{
		char	   *fc_val = pstrdup(fc_fname);

		fc__state->action(fc__state->action_state, fc_val, strlen(fc_val));
	}
}

/*
 * 遍历 jsonb，并对每个字符串值或元素应用指定的
 * JsonTransformStringValuesAction。任何必要的上下文
 * 可以在 action_state 变量中传递给 JsonTransformStringValuesAction。
 * 函数返回一个原始 jsonb 对象的副本，并具有转换后的值。
 */
Jsonb *
transform_jsonb_string_values(Jsonb *fc_jsonb, void *fc_action_state,
							  JsonTransformStringValuesAction fc_transform_action)
{
	JsonbIterator *fc_it;
	JsonbValue	fc_v,
			   *fc_res = NULL;
	JsonbIteratorToken fc_type;
	JsonbParseState *fc_st = NULL;
	text	   *fc_out;
	bool		fc_is_scalar = false;

	fc_it = JsonbIteratorInit(&fc_jsonb->root);
	fc_is_scalar = fc_it->isScalar;

	while ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) != WJB_DONE)
	{
		if ((fc_type == WJB_VALUE || fc_type == WJB_ELEM) && fc_v.type == jbvString)
		{
			fc_out = fc_transform_action(fc_action_state, fc_v.val.string.val, fc_v.val.string.len);
			/* out 可能没有被 toasted，但让我们确认一下 */
			fc_out = pg_detoast_datum_packed(fc_out);
			fc_v.val.string.val = VARDATA_ANY(fc_out);
			fc_v.val.string.len = VARSIZE_ANY_EXHDR(fc_out);
			fc_res = pushJsonbValue(&fc_st, fc_type, fc_type < WJB_BEGIN_ARRAY ? &fc_v : NULL);
		}
		else
		{
			fc_res = pushJsonbValue(&fc_st, fc_type, (fc_type == WJB_KEY ||
											 fc_type == WJB_VALUE ||
											 fc_type == WJB_ELEM) ? &fc_v : NULL);
		}
	}
#ifdef FDD//cppcheck
	if (!fc_res)
		return NULL;
#endif
	if (fc_res->type == jbvArray)
		fc_res->val.array.rawScalar = fc_is_scalar;

	return JsonbValueToJsonb(fc_res);
}

/*
 * 遍历 json，并对每个字符串值或元素应用指定的
 * JsonTransformStringValuesAction。任何必要的上下文
 * 可以在 action_state 变量中传递给 JsonTransformStringValuesAction。
 * 函数返回一个 StringInfo，它是原始 json 的副本，具有
 * 转换后的值。
 */
text * transform_json_string_values(text *fc_json, void *fc_action_state,
							 JsonTransformStringValuesAction fc_transform_action)
{
	JsonLexContext *fc_lex = makeJsonLexContext(fc_json, true);
	JsonSemAction *fc_sem = palloc0(sizeof(JsonSemAction));
	TransformJsonStringValuesState *fc_state = palloc0(sizeof(TransformJsonStringValuesState));

	fc_state->lex = fc_lex;
	fc_state->strval = makeStringInfo();
	fc_state->action = fc_transform_action;
	fc_state->action_state = fc_action_state;

	fc_sem->semstate = (void *) fc_state;
	fc_sem->scalar = fc_transform_string_values_scalar;
	fc_sem->object_start = fc_transform_string_values_object_start;
	fc_sem->object_end = fc_transform_string_values_object_end;
	fc_sem->array_start = fc_transform_string_values_array_start;
	fc_sem->array_end = fc_transform_string_values_array_end;
	fc_sem->scalar = fc_transform_string_values_scalar;
	fc_sem->array_element_start = fc_transform_string_values_array_element_start;
	fc_sem->object_field_start = fc_transform_string_values_object_field_start;

	pg_parse_json_or_ereport(fc_lex, fc_sem);

	return cstring_to_text_with_len(fc_state->strval->data, fc_state->strval->len);
}

/*
 * transform_json_string_values 的辅助函数集，用于为所有值调用
 * 指定的 JsonTransformStringValuesAction，并且让其他所有
 * 内容保持不变。
 */
static void fc_transform_string_values_object_start(void *fc_state)
{
	TransformJsonStringValuesState *fc__state = (TransformJsonStringValuesState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, '{');
}

static void fc_transform_string_values_object_end(void *fc_state)
{
	TransformJsonStringValuesState *fc__state = (TransformJsonStringValuesState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, '}');
}

static void fc_transform_string_values_array_start(void *fc_state)
{
	TransformJsonStringValuesState *fc__state = (TransformJsonStringValuesState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, '[');
}

static void fc_transform_string_values_array_end(void *fc_state)
{
	TransformJsonStringValuesState *fc__state = (TransformJsonStringValuesState *) fc_state;

	appendStringInfoCharMacro(fc__state->strval, ']');
}

static void fc_transform_string_values_object_field_start(void *fc_state, char *fc_fname, bool fc_isnull)
{
	TransformJsonStringValuesState *fc__state = (TransformJsonStringValuesState *) fc_state;

	if (fc__state->strval->data[fc__state->strval->len - 1] != '{')
		appendStringInfoCharMacro(fc__state->strval, ',');

	/*
	 * 不幸的是，我们不再拥有带引号和转义的字符串，因此
	 * 我们必须重新进行转义。
	 */
	escape_json(fc__state->strval, fc_fname);
	appendStringInfoCharMacro(fc__state->strval, ':');
}

static void fc_transform_string_values_array_element_start(void *fc_state, bool fc_isnull)
{
	TransformJsonStringValuesState *fc__state = (TransformJsonStringValuesState *) fc_state;

	if (fc__state->strval->data[fc__state->strval->len - 1] != '[')
		appendStringInfoCharMacro(fc__state->strval, ',');
}

static void fc_transform_string_values_scalar(void *fc_state, char *fc_token, JsonTokenType fc_tokentype)
{
	TransformJsonStringValuesState *fc__state = (TransformJsonStringValuesState *) fc_state;

	if (fc_tokentype == JSON_TOKEN_STRING)
	{
		text	   *fc_out = fc__state->action(fc__state->action_state, fc_token, strlen(fc_token));

		escape_json(fc__state->strval, text_to_cstring(fc_out));
	}
	else
		appendStringInfoString(fc__state->strval, fc_token);
}
